好的 - 我几乎不好意思在这里张贴这个(如果有人投票,我会删除)这似乎是一个基本问题。
这是在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;
}
答案 0 :(得分:144)
这适用于正数,不确定是负数。它只使用整数数学。
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;
}
答案 1 :(得分:94)
无条件:
int roundUp(int numToRound, int multiple)
{
assert(multiple);
return ((numToRound + multiple - 1) / multiple) * multiple;
}
对于负数
,其效果类似于 rounding away from zero编辑:适用于负数的版本
int roundUp(int numToRound, int multiple)
{
assert(multiple);
int isPositive = (int)(numToRound >= 0);
return ((numToRound + isPositive * (multiple - 1)) / multiple) * multiple;
}
如果multiple
是2的幂
int roundUp(int numToRound, int multiple)
{
assert(multiple && ((multiple & (multiple - 1)) == 0));
return (numToRound + multiple - 1) & -multiple;
}
答案 2 :(得分:35)
当因子始终为正时,这是有效的:
int round_up(int num, int factor)
{
return num + factor - 1 - (num - 1) % factor;
}
编辑:返回round_up(0,100)=100
。请参阅下面的Paul的评论,以获得返回round_up(0,100)=0
的解决方案。
答案 3 :(得分:22)
这是对“如何找出n位将占用多少字节?(A:(n bits + 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
}
答案 4 :(得分:14)
int roundUp(int numToRound, int multiple)
{
if(multiple == 0)
{
return 0;
}
return ((numToRound - 1) / multiple + 1) * multiple;
}
无需乱搞条件
答案 5 :(得分: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;
}
这适用于任何浮点数或基数(例如,您可以将-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;
}
这或多或少是基座的答案,增加了负面的输入支持。
答案 6 :(得分:7)
这是使用模板函数的现代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));
}
要创建向上舍入的函数,请使用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));
}
创建“向下舍入”或更好地称为“圆底”模板功能,如下所示:
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));
}
答案 7 :(得分:7)
对于任何寻找简短而甜蜜答案的人。这是我用的。没有说明负面因素。
n - (n % r)
这将返回上一个因素。
(n + r) - (n % r)
将返回下一个。希望这有助于某人。 :)
答案 8 :(得分:5)
首先,你的错误条件(倍数== 0)应该有一个返回值。什么?我不知道。也许你想抛出异常,这取决于你。但是,什么都不返回是危险的。
其次,您应该检查numToRound是否已经是倍数。否则,当您将multiple
添加到roundDown
时,您将得到错误的答案。
第三,你的演员是错的。您将numToRound
转换为整数,但它已经是整数。你需要在除法之前强制转换为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);
}
答案 9 :(得分:4)
以防任何人需要求解正数的解决方案四舍五入到最接近的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在线):
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
这些说明中的每一条都 非常快 ,因此功能也非常快。由于代码非常小而且快速,因此在使用它时inline
函数可能很有用。
信用:
答案 10 :(得分:3)
我正在使用:
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)
}
请注意,这两个圆形负值都朝向零(这意味着所有值都是圆形到正无穷大),它们都不依赖于有符号溢出(在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
答案 11 :(得分:2)
int noOfMultiples = int((numToRound / multiple)+0.5);
return noOfMultiples*multiple
C ++将每个数字向下舍入,因此如果你加0.5(如果它的1.5将是2),但1.49将是1.99因此1。
编辑 - 抱歉没有看到你想要整理,我建议使用ceil()方法而不是+0.5
答案 12 :(得分:2)
始终围捕
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) - &gt; 10
alwaysRoundUp(5,10) - &gt; 10
alwaysRoundUp(10,10) - &gt; 10
要始终向下舍入
int alwaysRoundDown(int n, int multiple)
{
n = (n / multiple) * multiple;
return n;
}
alwaysRoundDown(1,10) - &gt; 0
alwaysRoundDown(5,10) - &gt; 0
alwaysRoundDown(10,10) - &gt; 10
绕过正常方式
int normalRound(int n, int multiple)
{
n = ((n + multiple/2)/multiple) * multiple;
return n;
}
normalRound(1,10) - &gt; 0
normalRound(5,10) - &gt; 10
normalRound(10,10) - &gt; 10
答案 13 :(得分:2)
可能会有所帮助:
int RoundUpToNearestMultOfNumber(int val, int num)
{
assert(0 != num);
return (floor((val + num) / num) * num);
}
答案 14 :(得分:2)
int roundUp = roundDown + multiple;
int roundCalc = roundUp;
return (roundCalc);
绝对可以缩短为
int roundUp = roundDown + multiple;
return roundUp;
答案 15 :(得分:2)
使用ceil()可能更安全地使用ceil() - 除非你知道int除法会产生正确的结果。
答案 16 :(得分:1)
对于负数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);
}
答案 17 :(得分:1)
这就是我要做的事情:
#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;
}
代码可能不是最佳的,但我更喜欢干净的代码而不是干性能。
答案 18 :(得分:1)
舍入到最接近的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
答案 19 :(得分:1)
我找到了一个类似于上面发布的算法的算法:
int [(| x | + n-1)/ n] * [(nx)/ | x |],其中x是用户输入值,n是正在使用的倍数。
适用于所有值x,其中x是整数(正数或负数,包括零)。我是专门为C ++程序编写的,但基本上可以用任何语言实现。
答案 20 :(得分:1)
int roundUp (int numToRound, int multiple)
{
return multiple * ((numToRound + multiple - 1) / multiple);
}
虽然:
建议使用无符号整数,它定义了溢出行为。
你会得到一个例外是多个== 0,但在这种情况下它并不是一个明确定义的问题。
答案 21 :(得分:1)
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} ))
}
答案 22 :(得分:1)
如果x
已经是倍数,我会使用模数组合来取消余数的添加:
int round_up(int x, int div)
{
return x + (div - x % div) % div;
}
我们找到余数的倒数,然后用除数再次使其无效,如果它是除数本身,则添加x
。
round_up(19, 3) = 21
答案 23 :(得分:1)
这是我根据OP的建议以及其他所有人提供的示例得出的解决方案。由于大多数人都在寻找可处理负数的方法,因此该解决方案可以做到这一点,而无需使用任何特殊功能,例如abs等。
通过四舍五入,通过避免模数并使用除法,负数是自然的结果。在计算出四舍五入后的版本之后,它会执行所需的数学运算以朝负方向或朝正方向四舍五入。
还请注意,由于没有使用特殊函数来计算任何东西,因此那里的速度有所提高。
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;
}
答案 24 :(得分:0)
无穷无尽的可能性,仅适用于有符号整数:
n +((r-n)%r)
答案 25 :(得分:0)
我认为这可行:
int roundUp(int numToRound, int multiple) {
return multiple? !(numToRound%multiple)? numToRound : ((numToRound/multiple)+1)*multiple: numToRound;
}
答案 26 :(得分:0)
我认为这应该对您有帮助。我已经用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;
}
答案 27 :(得分: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
答案 28 :(得分:0)
/// 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) );
}}
}
答案 29 :(得分:-1)
这对我有用,但没有尝试处理否定
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;
}
答案 30 :(得分:-3)
这里是展示优雅概念的超级简单解决方案。基本上是用于网格捕捉的。
(伪代码)
nearestPos = Math.Ceil( numberToRound / multiple ) * multiple;