Reputation: 1072
I need to round integers to be the nearest multiple of another integer. Examples for results in the case of multiples of 100:
and so on.
I came up with the following code, that works, but feels "dirty":
int RoundToMultiple(int toRound, int multiple)
{
return (toRound + (multiple / 2)) / multiple * multiple;
}
This counts on the truncating properties of integer division to make it work. Can I count on this code to be portable? Are there any compiler setups where this will fail to give me the desired result? If there are, how can I achieve the same results in a portable way?
If needed for a better answer, it can be assumed that multiples will be powers of 10 (including multiples of 1). Numbers can also be assumed to all be positive.
Upvotes: 7
Views: 2122
Reputation: 29017
Yes, you can count on this code to be portable. N4296 (which is the latest open draft of C++14) says in section 5.6 [expr.mul]:
For integral operands the / operator yields the algebraic quotient with any fractional part discarded. [Footnote: This is often called truncation towards zero]
This is not a new feature of the latest C++, it could be relied on in C89 too.
The only caveat, is that if toRound
is negative, you need to subtract the offset.
An alternative approach is:
int RoundToMultiple(int toRound, int multiple)
{
const auto ratio = static_cast<double>(toRound) / multiple;
const auto iratio = std::lround(ratio);
return iratio * multiple;
}
This avoid messy +/- offsets, but performance will be worse, and there are problems if toRound
is so large that it can't be held precisely in a double. (OTOH, if this is for output, then I suspect multiple
will be similarly large in this case, so you will be alright.)
Upvotes: 4
Reputation: 35164
Though - as mentioned by others - the integral division behaves as you expect, may be the following solution looks "less wired" (still opinion based).
Concerning a solution that converts an int to a double: I personally feel that this is to expensive just for the sake of rounding, but maybe someone can convince me that my feeling is wrong;
Anyway, by using just integral operators, the following solution makes the discussion on whether a double
's mantissa can always hold every int
superfluous:
int RoundToMultiple(int toRound, int multiple) {
toRound += multiple / 2;
return toRound - (toRound%multiple);
}
If you also wanted to include negative values, the code could be slightly adapted as follows (including tests):
#include <stdio.h>
int RoundToMultiple(int toRound, int multiple) {
toRound += toRound < 0 ? -multiple / 2 : multiple / 2;
return toRound - (toRound%multiple);
}
int main(int argc, char const *argv[])
{
int tests[] = { 36,99,123,164,-36,-99,-123,-164,0 };
int expectedResults[] = { 0,100,100,200,0,-100,-100,-200,0 };
int i=0;
int test=0, result=0, expectedResult=0;
do {
test = tests[i];
result = RoundToMultiple(test, 100);
expectedResult = expectedResults[i];
printf("test %d: %d==%d ? %s\n", test, result, expectedResult, (expectedResult==result ? "OK" : "NOK!"));
i++;
}
while(test != 0);
}
Upvotes: 0
Reputation: 118435
The C++ standard explicitly specifies the behavior of integer division thusly:
[expr.mul]
For integral operands the / operator yields the algebraic quotient with any fractional part discarded.
A.k.a. truncation towards zero. This is as portable as it gets.
Upvotes: 2