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