好吧——我几乎不好意思在这里张贴这个(如果有人投票关闭,我会删除),因为这似乎是一个基本的问题。
这是在c++中四舍五入到一个数字的倍数的正确方法吗?
我知道还有其他与此相关的问题,但我特别感兴趣的是,在c++中做这件事的最佳方法是什么:
int roundUp(int numToRound, int multiple)
{
if(multiple == 0)
{
return numToRound;
}
int roundDown = ( (int) (numToRound) / multiple) * multiple;
int roundUp = roundDown + multiple;
int roundCalc = roundUp;
return (roundCalc);
}
更新:
抱歉,我可能没把意思说清楚。下面是一些例子:
roundUp(7, 100)
//return 100
roundUp(117, 100)
//return 200
roundUp(477, 100)
//return 500
roundUp(1077, 100)
//return 1100
roundUp(52, 20)
//return 60
roundUp(74, 30)
//return 90
首先,错误条件(multiple == 0)应该有一个返回值。什么?我不知道。也许您想要抛出一个异常,这取决于您。但是,什么都不返回是危险的。
其次,您应该检查numToRound是否已经是一个倍数。否则,当您在roundDown中添加倍数时,您将得到错误的答案。
第三,你的角色选择是错误的。您将numToRound转换为一个整数,但它已经是一个整数。需要在除法之前强制转换为to double,在乘法之后强制转换回int。
最后,负数需要什么?舍入“向上”可以表示舍入到零(与正数方向相同),或远离零(一个“更大”的负数)。或者,也许你不在乎。
以下是前三个修复的版本,但我不处理负面问题:
int roundUp(int numToRound, int multiple)
{
if(multiple == 0)
{
return 0;
}
else if(numToRound % multiple == 0)
{
return numToRound
}
int roundDown = (int) (( (double) numToRound / multiple ) * multiple);
int roundUp = roundDown + multiple;
int roundCalc = roundUp;
return (roundCalc);
}
我用的是:
template <class _Ty>
inline _Ty n_Align_Up(_Ty n_x, _Ty n_alignment)
{
assert(n_alignment > 0);
//n_x += (n_x >= 0)? n_alignment - 1 : 1 - n_alignment; // causes to round away from zero (greatest absolute value)
n_x += (n_x >= 0)? n_alignment - 1 : -1; // causes to round up (towards positive infinity)
//n_x += (_Ty(-(n_x >= 0)) & n_alignment) - 1; // the same as above, avoids branch and integer multiplication
//n_x += n_alignment - 1; // only works for positive numbers (fastest)
return n_x - n_x % n_alignment; // rounds negative towards zero
}
对于2的幂:
template <class _Ty>
bool b_Is_POT(_Ty n_x)
{
return !(n_x & (n_x - 1));
}
template <class _Ty>
inline _Ty n_Align_Up_POT(_Ty n_x, _Ty n_pot_alignment)
{
assert(n_pot_alignment > 0);
assert(b_Is_POT(n_pot_alignment)); // alignment must be power of two
-- n_pot_alignment;
return (n_x + n_pot_alignment) & ~n_pot_alignment; // rounds towards positive infinity (i.e. negative towards zero)
}
请注意,这两个负值都舍入到0(这意味着所有值都舍入到正无穷),它们都不依赖于有符号溢出(这在C/ c++中未定义)。
这给:
n_Align_Up(10, 100) = 100
n_Align_Up(110, 100) = 200
n_Align_Up(0, 100) = 0
n_Align_Up(-10, 100) = 0
n_Align_Up(-110, 100) = -100
n_Align_Up(-210, 100) = -200
n_Align_Up_POT(10, 128) = 128
n_Align_Up_POT(130, 128) = 256
n_Align_Up_POT(0, 128) = 0
n_Align_Up_POT(-10, 128) = 0
n_Align_Up_POT(-130, 128) = -128
n_Align_Up_POT(-260, 128) = -256
float roundUp(float number, float fixedBase) {
if (fixedBase != 0 && number != 0) {
float sign = number > 0 ? 1 : -1;
number *= sign;
number /= fixedBase;
int fixedPoint = (int) ceil(number);
number = fixedPoint * fixedBase;
number *= sign;
}
return number;
}
这适用于任何浮点数或基数(例如,你可以四舍五入到最接近的6.75)。本质上,它是转换到定点,四舍五入,然后转换回来。它通过舍入0来处理负号。它还通过将函数转换为roundDown来处理值的负舍入。
int特定的版本如下所示:
int roundUp(int number, int fixedBase) {
if (fixedBase != 0 && number != 0) {
int sign = number > 0 ? 1 : -1;
int baseSign = fixedBase > 0 ? 1 : 0;
number *= sign;
int fixedPoint = (number + baseSign * (fixedBase - 1)) / fixedBase;
number = fixedPoint * fixedBase;
number *= sign;
}
return number;
}
这或多或少是plinth的答案,加上负输入支持。