我需要将整数舍入为另一个整数的最接近的倍数。在100的倍数的情况下结果的示例:
等等。
我提出了以下代码,但是感觉“很脏”:
int RoundToMultiple(int toRound, int multiple)
{
return (toRound + (multiple / 2)) / multiple * multiple;
}
这依赖于整数除法的截断属性以使其有效。 我可以指望这个代码是可移植的吗?是否有任何编译器设置,这将无法给我所需的结果?如果有,我怎样才能以便携的方式获得相同的结果?
如果需要更好的答案,可以假设倍数将是10的幂(包括1的倍数)。数字也可以假设都是正数。
答案 0 :(得分:4)
是的,您可以指望此代码可移植。 N4296(这是C ++ 14的最新公开草案)在第5.6节[expr.mul]中说:
有关 积分操作数/运算符产生代数商,丢弃任何小数部分。 [脚注:这通常被称为截断为零]
这不是最新C ++的新功能,它也可以在C89中使用。
唯一需要注意的是,如果toRound
否定,则需要减去偏移量。
另一种方法是:
int RoundToMultiple(int toRound, int multiple)
{
const auto ratio = static_cast<double>(toRound) / multiple;
const auto iratio = std::lround(ratio);
return iratio * multiple;
}
这可以避免凌乱的+/-偏移,但性能会更差,如果toRound
如此之大以至于无法精确地保持在双精度中,则会出现问题。 (OTOH,如果这是输出,那么我怀疑multiple
在这种情况下会同样大,所以你会没事的。)
答案 1 :(得分:2)
C ++标准明确地指定了整数除法的行为:
[expr.mul]
对于积分操作数,/运算符产生代数 弃去任何小数部分的商。
A.k.a。截断为零。这是便携式的。
答案 2 :(得分:0)
虽然 - 正如其他人所说 - 积分除法表现得如你所愿,可能是以下解决方案看起来&#34;更少有线&#34; (仍以意见为基础)。
关于将int转换为double的解决方案:我个人觉得这只是为了四舍五入而昂贵,但也许有人可以说服我,我的感觉是错的;
无论如何,通过仅使用整数运算符,以下解决方案讨论了double
的尾数是否总能保持每个int
多余:
int RoundToMultiple(int toRound, int multiple) {
toRound += multiple / 2;
return toRound - (toRound%multiple);
}
如果您还想包含负值,可以按如下方式(包括测试)略微调整代码:
#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);
}