好吧——我几乎不好意思在这里张贴这个(如果有人投票关闭,我会删除),因为这似乎是一个基本的问题。

这是在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

当前回答

以下是我根据OP的建议和其他人给出的例子给出的解决方案。因为大多数人都在寻找它来处理负数,这个解决方案就是这样做的,而不使用任何特殊的功能,如腹肌等。

通过避免使用模数而使用除法,负数是一个自然的结果,尽管它是四舍五入。在计算出向下舍入的版本之后,它会执行所需的数学运算以向上舍入,或者向负方向舍入,或者向正方向舍入。

还要注意的是,没有使用特殊的函数来计算任何东西,所以这里有一个小的速度提升。

int RoundUp(int n, int multiple)
{
    // prevent divide by 0 by returning n
    if (multiple == 0) return n;

    // calculate the rounded down version
    int roundedDown = n / multiple * multiple;

    // if the rounded version and original are the same, then return the original
    if (roundedDown == n) return n;

    // handle negative number and round up according to the sign
    // NOTE: if n is < 0 then subtract the multiple, otherwise add it
    return (n < 0) ? roundedDown - multiple : roundedDown + multiple;
}

其他回答

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的答案,加上负输入支持。

首先,因为我不太明白你想要做什么,这些台词

int roundUp = roundDown + multiple;
int roundCalc = roundUp;
return (roundCalc); 

肯定可以缩写为

int roundUp = roundDown + multiple;
return roundUp;

这是使用模板函数的现代c++方法,该模板函数适用于float, double, long, int和short(但不适用于long long和long double,因为使用了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;
}

但是你可以很容易地通过模板专门化添加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));
}

要创建向上舍入的函数,请使用std::ceil,而总是向下舍入的函数请使用std::floor。上面的例子是使用std::round进行舍入。

创建“round up”或更广为人知的“round ceiling”模板函数,如下所示:

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));
}

创建“round down”或更广为人知的“round floor”模板函数,如下所示:

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));
}

总是四舍五入

int alwaysRoundUp(int n, int multiple)
{
    if (n % multiple != 0) {
        n = ((n + multiple) / multiple) * multiple;

        // Another way
        //n = n - n % multiple + multiple;
    }

    return n;
}

一生(1,10)-> 10

一生(5,10)-> 10

-> 10 -> 10


总是四舍五入

int alwaysRoundDown(int n, int multiple)
{
    n = (n / multiple) * multiple;

    return n;
}

一直循环(1,10)-> 0

一直循环(5、10)-> 0

一直循环(10,10)-> 10


以正常的方式圆

int normalRound(int n, int multiple)
{
    n = ((n + multiple/2)/multiple) * multiple;

    return n;
}

正常回合(1, 10) -> 0

normalRound(5、10)-> 10

normalRound(10,10) -> 10

如果x已经是一个倍数,我使用模的组合来取消余数的加法:

int round_up(int x, int div)
{
    return x + (div - x % div) % div;
}

我们求余数的倒数然后再用除数求模如果它是除数本身,再加上x。

round_up(19, 3) = 21