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

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

这是正确的方法,以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 

编辑:感谢所有的答复。 这是我去的:

 int roundUp(int numToRound, int multiple) { if(multiple == 0) { return numToRound; } int remainder = numToRound % multiple; if (remainder == 0) { return numToRound; } return numToRound + multiple - remainder; } 

这适用于正数,不确定负数。 它只使用整数math。

 int roundUp(int numToRound, int multiple) { if (multiple == 0) return numToRound; int remainder = numToRound % multiple; if (remainder == 0) return numToRound; return numToRound + multiple - remainder; } 

编辑:这是一个版本,与负数工作,如果通过“向上”,你的意思是总是> =input的结果。

 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) { assert(multiple); return ((numToRound + multiple - 1) / multiple) * multiple; } 

这样的工作就像负数减去

编辑:也适用于负数的版本

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

testing


如果multiple是2的幂

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

testing

当因素总是正面的时候,这是有效的:

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

这是“如何找出n个比特需要多less个字节?(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 0; } return ((numToRound - 1) / multiple + 1) * multiple; } 

而且没有必要搞乱条件

对于任何寻找简短而甜蜜的答案的人。 这是我用的。 没有会计负面。

 n - (n % r) 

这将返回以前的因素。

 (n + r) - (n % r) 

将返回下一个。 希望这有助于某人。 🙂

 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)。 从本质上说,它正在转化为定点,在那里四舍五入,然后转换回来。 它通过将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; } 

这或多或less是基础的答案,增加了负面的投入支持。

这是使用模板函数的现代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; } 

但是您可以轻松地添加对模板专业化的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)); } 

要创build四舍五入的函数,请使用std::ceil并始终std::ceil使用std::floor 。 我从上面的例子是四舍五入使用std::round

创build“圆形”或更好地称为“圆形天花板”模板function,如下所示:

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

创build“下舍入”或更好地称为“圆楼”模板function,如下所示:

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

首先,你的错误条件(多个== 0)应该可能有一个返回值。 什么? 我不知道。 也许你想抛出exception,这取决于你。 但是,没有返回是危险的。

其次,你应该检查numToRound是不是一个倍数。 否则,当你添加multiple roundDown ,你会得到错误的答案。

第三,你的演员是错的。 你把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); } 

我在用着:

 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 } 

和两个幂:

 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 (ie negative towards zero) } 

请注意,这两个圆的负值趋向于零(这意味着所有值都为正无穷大),它们都不依赖于有符号溢出(在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 

可能更安全的投到浮动和使用ceil() – 除非你知道int分区将产生正确的结果。

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

C ++将每个数字向下舍入,所以如果你加0.5(如果它的1.5将是2),但是1.49将是1.99,因此是1。

编辑 – 抱歉没有看到你想要收集,我会build议使用ceil()方法,而不是+0.5

一件事,因为我真的不明白你想做什么,线条

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

绝对可以缩短到

 int roundUp = roundDown + multiple; return roundUp; 

可能会有这个帮助:

 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

回归两权:

以防万一任何人需要一个正数的解决scheme,四舍五入到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; } 

input号码将保持不变,如果它已经是一个倍数。

这是GCC给出的-O2-Os的x86_64输出(9Sep2013 Build-godbolt GCC在线):

 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

每个指令都非常快 ,所以function也非常快。 由于代码非常小巧,所以在使用代码时可能会很有用。


信用:

  • algorithm:Hagen von Eitzen @ Math.SE
  • Godbolt交互式编译器 : @ GitHub上的@ mattgodbolt / gcc-explorer

我发现了一个与上面发布的algorithm有点相似的algorithm:

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

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

对于负数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); } 

这是我会做的:

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

代码可能不是最佳的,但我比干性能更喜欢干净的代码。

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

虽然:

  • 将不适用于负数
  • 如果numRound +多个溢出将不起作用

会build议使用无符号整数来代替溢出行为。

你会得到一个exception是多个== 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} )) } 

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

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

我们find余数的逆matrix,除数再除以零,如果它是除数本身,则加上x

 round_up(19, 3) = 21 
 /// 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 <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 

这适用于我,但没有尝试处理负面情况

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