C++:向上舍入到最接近的数字的倍数

Rob*_*boy 155 c++ algorithm rounding

好的 - 我几乎不好意思在这里张贴这个(如果有人投票结束我会删除),因为这似乎是一个基本问题.

这是在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);
}
Run Code Online (Sandbox Code Playgroud)

更新:对不起我可能没有明确意图.这里有些例子:

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
Run Code Online (Sandbox Code Playgroud)

编辑:感谢所有的回复.这是我的目的:

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);
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*som 149

这适用于正数,不确定负数.它只使用整数数学.

int roundUp(int numToRound, int multiple)
{
    if (multiple == 0)
        return numToRound;

    int remainder = numToRound % multiple;
    if (remainder == 0)
        return numToRound;

    return numToRound + multiple - remainder;
}
Run Code Online (Sandbox Code Playgroud)

编辑:这是一个使用负数的版本,如果用"向上"表示结果总是> =输入.

int roundUp(int numToRound, int multiple)
{
    if (multiple == 0)
        return numToRound;

    int remainder = abs(numToRound) % multiple;
    if (remainder == 0)
        return numToRound;

    if (numToRound < 0)
        return -(abs(numToRound) - remainder);
    else
        return numToRound + multiple - remainder;
}
Run Code Online (Sandbox Code Playgroud)

  • @Josh:为什么要使用乘法?`if(number <0)multiple = -multiple`更容易. (4认同)

Kin*_*gon 99

没有条件:

int roundUp(int numToRound, int multiple) 
{
    assert(multiple);
    return ((numToRound + multiple - 1) / multiple) * multiple;
}
Run Code Online (Sandbox Code Playgroud)

对于负数,这类似于从零开始舍入

编辑:适用于负数的版本

int roundUp(int numToRound, int multiple) 
{
    assert(multiple);
    int isPositive = (int)(numToRound >= 0);
    return ((numToRound + isPositive * (multiple - 1)) / multiple) * multiple;
}
Run Code Online (Sandbox Code Playgroud)

测试


如果multiple是2的幂

int roundUp(int numToRound, int multiple) 
{
    assert(multiple && ((multiple & (multiple - 1)) == 0));
    return (numToRound + multiple - 1) & -multiple;
}
Run Code Online (Sandbox Code Playgroud)

测试

  • +1为2版本的力量.非常有用,因为它完全避免了乘法,除法或模数的成本. (19认同)
  • 注意,对于二进制补码运算,`&〜(x - 1)`与`&-x`相同. (4认同)

小智 36

当因子始终为正时,这种方法有效:

int round_up(int num, int factor)
{
    return num + factor - 1 - (num - 1) % factor;
}
Run Code Online (Sandbox Code Playgroud)

编辑:返回round_up(0,100)=100.请参阅下面的保罗评论,以获得返回的解决方案round_up(0,100)=0.

  • 不应该是`num + factor - 1 - (num + factor - 1)%factor`? (6认同)
  • `num - 1 - (num - 1)%factor + factor`执行相同的计算,没有整数溢出的风险. (4认同)
  • round_up(0,100)== 100,而不是在接受的答案中为0 (3认同)
  • 看起来是处理“已经多个”情况的最短情况。 (2认同)

pli*_*nth 22

这是对"如何找出n位将占用多少字节?"(A:(n位+7)/ 8)的问题的概括.

int RoundUp(int n, int roundTo)
{
    // fails on negative?  What does that mean?
    if (roundTo == 0) return 0;
    return ((n + roundTo - 1) / roundTo) * roundTo; // edit - fixed error
}
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢这个解决方案,因为如果roundTo将是2的幂,你可以消除/和*并最终只得到便宜的操作(x = roundTo - 1; return(n + x)&~x;) (6认同)

dor*_*ron 14

int roundUp(int numToRound, int multiple)
{
 if(multiple == 0)
 {
  return 0;
 }
 return ((numToRound - 1) / multiple + 1) * multiple;  
}
Run Code Online (Sandbox Code Playgroud)

而且无需乱搞条件


Dol*_*hin 9

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;
}
Run Code Online (Sandbox Code Playgroud)

这适用于任何浮点数或基数(例如,您可以将-4舍入到最接近的6.75).本质上,它转换为固定点,在那里四舍五入,然后转换回来.它通过将AWAY从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;
}
Run Code Online (Sandbox Code Playgroud)

这或多或少是基座的答案,增加了负面的输入支持.


aar*_*ond 8

对于任何寻找短而甜蜜答案的人.这是我用的.没有负面因素.

n - (n % r)
Run Code Online (Sandbox Code Playgroud)

这将返回先前的因素.

(n + r) - (n % r)
Run Code Online (Sandbox Code Playgroud)

将返回下一个.希望这有助于某人.:)

  • 当`n%r == 0`时,第二个表达式不起作用. (5认同)
  • 我认为重要的是要注意,即使数字已经是倍数,这也会返回下一个倍数。为了避免这种情况,必须首先检查“n % r”是否为零。 (2认同)

Flo*_*dis 8

这是使用模板函数的现代c ++方法,该函数适用于float,double,long,int和short(但由于使用了double值,因此不能用于long long和long double).

#include <cmath>
#include <iostream>

template<typename T>
T roundMultiple( T value, T multiple )
{
    if (multiple == 0) return value;
    return static_cast<T>(std::round(static_cast<double>(value)/static_cast<double>(multiple))*static_cast<double>(multiple));
}

int main()
{
    std::cout << roundMultiple(39298.0, 100.0) << std::endl;
    std::cout << roundMultiple(20930.0f, 1000.0f) << std::endl;
    std::cout << roundMultiple(287399, 10) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

但是,你可以轻松地添加支持long long,并long double与模板特,如下图所示:

template<>
long double roundMultiple<long double>( long double value, long double multiple)
{
    if (multiple == 0.0l) return value;
    return std::round(value/multiple)*multiple;
}

template<>
long long roundMultiple<long long>( long long value, long long multiple)
{
    if (multiple == 0.0l) return value;
    return static_cast<long long>(std::round(static_cast<long double>(value)/static_cast<long double>(multiple))*static_cast<long double>(multiple));
}
Run Code Online (Sandbox Code Playgroud)

要创建向上舍入的功能,请使用std::ceil并始终向下舍入使用std::floor.我上面的例子是四舍五入使用std::round.

创建"向上舍入"或更好地称为"圆形天花板"模板功能,如下所示:

template<typename T>
T roundCeilMultiple( T value, T multiple )
{
    if (multiple == 0) return value;
    return static_cast<T>(std::ceil(static_cast<double>(value)/static_cast<double>(multiple))*static_cast<double>(multiple));
}
Run Code Online (Sandbox Code Playgroud)

创建"向下舍入"或更好地称为"圆底"模板功能,如下所示:

template<typename T>
T roundFloorMultiple( T value, T multiple )
{
    if (multiple == 0) return value;
    return static_cast<T>(std::floor(static_cast<double>(value)/static_cast<double>(multiple))*static_cast<double>(multiple));
}
Run Code Online (Sandbox Code Playgroud)

  • 要注意,因为将int64_t转换为double可能是有损的,所以它不像它可能出现的那样类型泛型. (3认同)

Mik*_*ron 5

首先,您的错误条件(倍数== 0)应该具有返回值.什么?我不知道.也许你想抛出异常,这取决于你.但是,什么都不返回是危险的.

其次,你应该检查numToRound是否已经是一个倍数.否则,当你添加multipleroundDown,你会得到错误的答案.

第三,你的演员是错的.你转换numToRound为一个整数,但它已经是一个整数.你需要在除法之前转换为加倍,并在乘法之后转换回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);
}
Run Code Online (Sandbox Code Playgroud)

  • -1:转换为double是奇怪且不必要的. (2认同)