4

I'm working with the code that frequently uses some nontrivial optimizations. What is the

#define idiv(a, b) (((a) + (b) / 2) / (b))

used for? Why not simply

#define idiv(a, b) ((a)/(b) + 0.5)

Is it integer division overflow protection or something else?

Marek R
  • 32,568
  • 6
  • 55
  • 140
Alan Kazbekov
  • 1,105
  • 2
  • 12
  • 31

3 Answers3

5

Integer division truncates towards zero. Assuming (from the name of the macro, idiv) your arguments are of integer type, ((a)/(b) + 0.5) would be truncated before you got to the + 0.5, so you would always round down regardless.

(((a) + (b) / 2) / (b)) rounds up results greater than x.5, without using floating-point arithmetics.

Note: You tagged your question C++. In C++, you shouldn't "macro" anything, really. Check Marek's answer for a template solution (but also the caveat that it doesn't really work for negative values).

DevSolar
  • 67,862
  • 21
  • 134
  • 209
  • I would add that this is basically the same as `(int)((a/b) + 0.5)`, but without using floating-point arithmetic. – ciamej Feb 17 '20 at 13:33
  • @ciamej: If your input is `int` to begin with (as the name of the macro implies), your version would've truncated before you get to the `0.5`. (Amended answer.) – DevSolar Feb 17 '20 at 13:41
  • @DevSolar oh right, I meant `(int)((double)(a)/b + 0.5)` which I saw used a lot. Basically this macro does the same without conversion to floating point. – ciamej Feb 17 '20 at 14:21
5

Your suggested modification is not equivalent, because a/b is integer division when the parameters are integers. You should cast parameters to floating point first.

The first macro avoids conversion to floating point, which might be faster. Additionally, converting values to floating point and back to integer might lose precision, because not all integers can be represented exactly as floats.

VLL
  • 9,634
  • 1
  • 29
  • 54
5

This code is C macro what is consider a very bad practice in C++. In C++ you should use templates (some says that this is smarter macros).

template<typename T>
constexpr T idiv(T a, T b) {
    return (a + b / 2) / b;
}

Still this code doesn't do what author has expected. Plan was to round result to closest integer value, but it fails if one arguments has negative value.

See this and note failure for a: 4 b: -2

And there is also integer overflow issue (see last test case).

Marek R
  • 32,568
  • 6
  • 55
  • 140