四舍五入到一个数字的最接近倍数

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

这是在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);
}
< p >更新: 抱歉,我可能没把意思说清楚。下面是一些例子:

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
172245 次浏览

可能更安全的方法是强制转换为浮点数并使用ceil()—除非您知道int除法将产生正确的结果。

int noOfMultiples = int((numToRound / multiple)+0.5);
return noOfMultiples*multiple

c++把每个数字四舍五入,所以如果你加0.5(如果是1.5,就是2),但1.49就是1.99,所以是1。

编辑-抱歉没有看到你想四舍五入,我建议使用ceil()方法而不是+0.5

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

其次,您应该检查numToRound是否已经是一个倍数。否则,当你将multiple添加到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);
}

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

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

肯定可以缩写为

int roundUp = roundDown + multiple;
return roundUp;

这是对“如何求出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
}

这适用于正数,不适用于负数。它只使用整数数学。

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


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


return numToRound + multiple - remainder;
}

编辑:这里有一个适用于负数的版本,如果你所说的“上”是指一个总是>=输入的结果。

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;
}
int roundUp(int numToRound, int multiple)
{
if(multiple == 0)
{
return 0;
}
return ((numToRound - 1) / multiple + 1) * 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的答案,加上负输入支持。

当factor总是为正时,这种方法有效:

int round_up(int num, int factor)
{
return num + factor - 1 - (num + factor - 1) % factor;
}

编辑:返回round_up(0,100)=100。请参阅下面Paul的评论,了解返回round_up(0,100)=0的解决方案。

我发现了一个算法,有点类似于上面发布的:

Int [(|x|+n-1)/n]*[(nx)/|x|],其中x是用户输入的值,n是使用的倍数。

它适用于所有值x,其中x是整数(正或负,包括零)。我专门为c++程序编写了它,但基本上可以在任何语言中实现。

没有条件:

int roundUp(int numToRound, int multiple)
{
assert(multiple);
return ((numToRound + multiple - 1) / multiple) * multiple;
}

这类似于舍入from 0 对负数的处理


同样适用于负数的版本:

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

测试


如果multiple是2的幂(速度快3.7倍)

int roundUp(int numToRound, int multiple)
{
assert(multiple && ((multiple & (multiple - 1)) == 0));
return (numToRound + multiple - 1) & -multiple;
}

测试

这对我来说很管用,但我并没有试图处理消极的东西

public static int roundUp(int numToRound, int multiple) {
if (multiple == 0) {
return 0;
} else if (numToRound % multiple == 0) {
return numToRound;
}


int mod = numToRound % multiple;
int diff = multiple - mod;
return numToRound + diff;
}

对于负numToRound:

这应该很容易做到,但标准的模%运算符并不像人们期望的那样处理负数。例如- 14% 12 = -2而不是10。首先要做的是得到一个永不返回负数的模运算符。roundUp非常简单。

public static int mod(int x, int n)
{
return ((x % n) + n) % n;
}


public static int roundUp(int numToRound, int multiple)
{
return numRound + mod(-numToRound, multiple);
}

想要一个简短而甜蜜的答案的人。这是我用的。不考虑消极因素。

n - (n % r)

这将返回前一个因子。

(n + r) - (n % r)

将返回下一个。希望这能帮助到一些人。:)

这可能会有所帮助:

int RoundUpToNearestMultOfNumber(int val, int num)
{
assert(0 != num);
return (floor((val + num) / num) * num);
}

总是四舍五入

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


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


return n;
}

alwaysRoundUp(1,10) -> 10

alwaysRoundUp(5,10) -> 10

alwaysRoundUp(10,10) -> 10


总是四舍五入

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


return n;
}

alwaysRoundDown(1,10) -> 0

alwaysRoundDown(5, 10) -> 0

alwaysRoundDown(10,10) -> 10


以正常的方式圆

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


return n;
}

normalRound(1,10) -> 0

normalRound(5, 10) -> 10

normalRound(10,10) -> 10

/// Rounding up 'n' to the nearest multiple of number 'b'.
/// - Not tested for negative numbers.
/// \see http://stackoverflow.com/questions/3407012/
#define roundUp(n,b) ( (b)==0 ? (n) : ( ((n)+(b)-1) - (((n)-1)%(b)) ) )


/// \c test->roundUp().
void test_roundUp() {
// yes_roundUp(n,b) ( (b)==0 ? (n) : ( (n)%(b)==0 ? n : (n)+(b)-(n)%(b) ) )
// yes_roundUp(n,b) ( (b)==0 ? (n) : ( ((n + b - 1) / b) * b ) )


// no_roundUp(n,b) ( (n)%(b)==0 ? n : (b)*( (n)/(b) )+(b) )
// no_roundUp(n,b) ( (n)+(b) - (n)%(b) )


if (true) // couldn't make it work without (?:)
\{\{  // test::roundUp()
unsigned m;
{ m = roundUp(17,8); } ++m;
assertTrue( 24 == roundUp(17,8) );
{ m = roundUp(24,8); }
assertTrue( 24 == roundUp(24,8) );


assertTrue( 24 == roundUp(24,4) );
assertTrue( 24 == roundUp(23,4) );
{ m = roundUp(23,4); }
assertTrue( 24 == roundUp(21,4) );


assertTrue( 20 == roundUp(20,4) );
assertTrue( 20 == roundUp(19,4) );
assertTrue( 20 == roundUp(18,4) );
assertTrue( 20 == roundUp(17,4) );


assertTrue( 17 == roundUp(17,0) );
assertTrue( 20 == roundUp(20,0) );
}}
}

这就是我要做的:

#include <cmath>


int roundUp(int numToRound, int multiple)
{
// if our number is zero, return immediately
if (numToRound == 0)
return multiple;


// if multiplier is zero, return immediately
if (multiple == 0)
return numToRound;


// how many times are number greater than multiple
float rounds = static_cast<float>(numToRound) / static_cast<float>(multiple);


// determine, whether if number is multiplier of multiple
int floorRounds = static_cast<int>(floor(rounds));


if (rounds - floorRounds > 0)
// multiple is not multiplier of number -> advance to the next multiplier
return (floorRounds+1) * multiple;
else
// multiple is multiplier of number -> return actual multiplier
return (floorRounds) * multiple;
}

代码可能不是最优的,但比起枯燥的性能,我更喜欢干净的代码。

这将得到正整数的结果:

#include <iostream>
using namespace std;


int roundUp(int numToRound, int multiple);


int main() {
cout << "answer is: " << roundUp(7, 100) << endl;
cout << "answer is: " << roundUp(117, 100) << endl;
cout << "answer is: " << roundUp(477, 100) << endl;
cout << "answer is: " << roundUp(1077, 100) << endl;
cout << "answer is: " << roundUp(52,20) << endl;
cout << "answer is: " << roundUp(74,30) << endl;
return 0;
}


int roundUp(int numToRound, int multiple) {
if (multiple == 0) {
return 0;
}
int result = (int) (numToRound / multiple) * multiple;
if (numToRound % multiple) {
result += multiple;
}
return result;
}

这里是输出:

answer is: 100
answer is: 200
answer is: 500
answer is: 1100
answer is: 60
answer is: 90

这是使用模板函数的现代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 longlong 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 roundUp (int numToRound, int multiple)
{
return multiple * ((numToRound + multiple - 1) / multiple);
}

尽管:

  • 对负数不成立
  • 不会工作,如果numRound +多个溢出

建议使用无符号整数,这已经定义了溢出行为。

您将得到一个异常是multiple == 0,但在这种情况下,这不是一个定义良好的问题。

c:

int roundUp(int numToRound, int multiple)
{
return (multiple ? (((numToRound+multiple-1) / multiple) * multiple) : numToRound);
}

对于~/.bashrc:

roundup()
{
echo $(( ${2} ? ((${1}+${2}-1)/${2})*${2} : ${1} ))
}

四舍五入到2的幂:

以防有人需要一个正数四舍五入到2的幂的最近倍数的解(因为这就是我在这里结束的原因):

// number: the number to be rounded (ex: 5, 123, 98345, etc.)
// pow2:   the power to be rounded to (ex: to round to 16, use '4')
int roundPow2 (int number, int pow2) {
pow2--;                     // because (2 exp x) == (1 << (x -1))
pow2 = 0x01 << pow2;


pow2--;                     // because for any
//
// (x = 2 exp x)
//
// subtracting one will
// yield a field of ones
// which we can use in a
// bitwise OR


number--;                   // yield a similar field for
// bitwise OR
number = number | pow2;
number++;                   // restore value by adding one back


return number;
}

如果输入的数字已经是一个倍数,那么它将保持不变。

下面是GCC用-O2-Os给出的x86_64输出(9Sep2013 Build - godbolt GCC online):

roundPow2(int, int):
lea ecx, [rsi-1]
mov eax, 1
sub edi, 1
sal eax, cl
sub eax, 1
or  eax, edi
add eax, 1
ret

每一行C代码都与它在程序集中的行完全对应:http://goo.gl/DZigfX

这些指令都是< em >极快< / em >,所以这个函数也非常快。由于代码是如此的小和快速,在使用它时inline函数可能是有用的。


信贷:

我用的是:

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

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

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

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

round_up(19, 3) = 21

以下是我根据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;
}

我想这应该对你有帮助。我用C语言编写了下面的程序。

# include <stdio.h>
int main()
{
int i, j;
printf("\nEnter Two Integers i and j...");
scanf("%d %d", &i, &j);
int Round_Off=i+j-i%j;
printf("The Rounded Off Integer Is...%d\n", Round_Off);
return 0;
}

四舍五入到最接近的倍数,恰好是2的幂

unsigned int round(unsigned int value, unsigned int multiple){
return ((value-1u) & ~(multiple-1u)) + multiple;
}

这在沿中间线分配时很有用,其中您想要的舍入增量是2的幂,但结果值只需是它的倍数。在gcc上,这个函数体生成8条没有除法或分支的汇编指令。

round(  0,  16) ->   0
round(  1,  16) ->  16
round( 16,  16) ->  16
round(257, 128) -> 384 (128 * 3)
round(333,   2) -> 334

这里有一个超级简单的解决方案来展示优雅的概念。它主要用于网格快照。

(伪代码)

nearestPos = Math.Ceil( numberToRound / multiple ) * multiple;

我认为这是可行的:

int roundUp(int numToRound, int multiple) {
return multiple? !(numToRound%multiple)? numToRound : ((numToRound/multiple)+1)*multiple: numToRound;
}

无限的可能性,仅适用于有符号整数:

N + ((r - N) % r

公认的答案并不是很好,我想我应该在这个问题上尝试一下,这应该是你抛出的所有整数:

int round_up(int input, unsigned int multiple) {
if (input < 0) { return input - input % multiple; }
return input + multiple - (((input - 1) % multiple) + 1);
}

如果这个数是负的,这很简单,取余数并把它加到输入上,这就可以了。

如果这个数不是负的,你必须从倍数中减去余数,然后加上它来四舍五入。这样做的问题是,如果输入正好在一个倍数上,它仍然会被舍入到下一个倍数,因为multiple - 0 = multiple

为了解决这个问题,我们做了一个很酷的小技巧:在计算余数之前从输入中减去1,然后把它加回到结果的余数上。这不会影响任何东西,除非输入是倍数。在这种情况下,减去1将计算出前一个倍数的余数。再加1,就正好是这个倍数。很明显,从自身减去这个等于0,所以输入值不变。