C++:四舍五入到最接近的数字倍数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3407012/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C++: Rounding up to the nearest multiple of a number
提问by Robben_Ford_Fan_boy
OK - I'm almost embarrassed posting this here (and I will delete if anyone votes to close) as it seems like a basic question.
好的 - 我几乎不好意思在这里发帖(如果有人投票关闭,我会删除),因为这似乎是一个基本问题。
Is this the correct way to round up to a multiple of a number in C++?
这是在 C++ 中四舍五入到一个数字的倍数的正确方法吗?
I know there are other questions related to this but I am specficially interested to know what is the best way to do this in 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);
}
Update: Sorry I probably didn't make intention clear. Here are some examples:
更新:对不起,我可能没有明确意图。这里有些例子:
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
采纳答案by Mark Ransom
This works for positive numbers, not sure about negative. It only uses integer 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;
}
Edit: Here's a version that works with negative numbers, if by "up" you mean a result that's always >= the 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;
}
回答by KindDragon
Without conditions:
无条件:
int roundUp(int numToRound, int multiple)
{
assert(multiple);
return ((numToRound + multiple - 1) / multiple) * multiple;
}
This works like rounding away from zerofor negative numbers
这就像为负数从零舍入
EDIT: Version that works also for negative numbers
编辑:也适用于负数的版本
int roundUp(int numToRound, int multiple)
{
assert(multiple);
int isPositive = (int)(numToRound >= 0);
return ((numToRound + isPositive * (multiple - 1)) / multiple) * multiple;
}
If multiple
is a power of 2 (faster in ~3.7 times http://quick-bench.com/sgPEZV9AUDqtx2uujRSa3-eTE80)
如果multiple
是 2 的幂(在 ~3.7 倍http://quick-bench.com/sgPEZV9AUDqtx2uujRSa3-eTE80 中更快)
int roundUp(int numToRound, int multiple)
{
assert(multiple && ((multiple & (multiple - 1)) == 0));
return (numToRound + multiple - 1) & -multiple;
}
回答by xlq
This works when factor will always be positive:
当因子始终为正时,此方法有效:
int round_up(int num, int factor)
{
return num + factor - 1 - (num - 1) % factor;
}
Edit: This returns round_up(0,100)=100
. Please see Paul's comment below for a solution that returns round_up(0,100)=0
.
编辑:这将返回round_up(0,100)=100
. 请参阅下面 Paul 的评论,了解返回round_up(0,100)=0
.
回答by plinth
This is a generalization of the problem of "how do I find out how many bytes n bits will take? (A: (n bits + 7) / 8).
这是“我如何找出 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
}
回答by doron
int roundUp(int numToRound, int multiple)
{
if(multiple == 0)
{
return 0;
}
return ((numToRound - 1) / multiple + 1) * multiple;
}
And no need to mess around with conditions
并且不需要乱七八糟的条件
回答by Dolphin
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;
}
This works for any float number or base (e.g. you can round -4 to the nearest 6.75). In essence it is converting to fixed point, rounding there, then converting back. It handles negatives by rounding AWAY from 0. It also handles a negative round to value by essentially turning the function into roundDown.
这适用于任何浮点数或基数(例如,您可以将 -4 舍入到最接近的 6.75)。本质上它是转换为定点,在那里四舍五入,然后转换回来。它通过从 0 舍入 AWAY 来处理负数。它还通过基本上将函数转换为 roundDown 来处理负数舍入到值。
An int specific version looks like:
特定于 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;
}
Which is more or less plinth's answer, with the added negative input support.
这或多或少是底座的答案,增加了负输入支持。
回答by aaron-bond
For anyone looking for a short and sweet answer. This is what I used. No accounting for negatives.
对于任何寻求简短而甜蜜的答案的人。这是我用的。不考虑负数。
n - (n % r)
That will return the previous factor.
这将返回前一个因素。
(n + r) - (n % r)
Will return the next. Hope this helps someone. :)
下次还会再来。希望这可以帮助某人。:)
回答by Flovdis
This is the modern c++ approach using a template function which is working for float, double, long, int and short (but not for long long, and long double because of the used double values).
这是使用模板函数的现代 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;
}
But you can easily add support for long long
and long double
with template specialisation as shown below:
但是,你可以轻松地添加支持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));
}
To create functions to round up, use std::ceil
and to always round down use std::floor
. My example from above is rounding using std::round
.
要创建向上舍入、使用std::ceil
并始终向下舍入的函数,请使用std::floor
. 我上面的例子是使用std::round
.
Create the "round up" or better known as "round ceiling" template function as shown below:
创建“向上舍入”或更广为人知的“圆形天花板”模板函数,如下所示:
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));
}
Create the "round down" or better known as "round floor" template function as shown below:
创建“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));
}
回答by Mike Caron
First off, your error condition (multiple == 0) should probably have a return value. What? I don't know. Maybe you want to throw an exception, that's up to you. But, returning nothing is dangerous.
首先,您的错误条件(multiple == 0)可能应该有一个返回值。什么?我不知道。也许你想抛出一个异常,这取决于你。但是,什么都不返回是危险的。
Second, you should check that numToRound isn't already a multiple. Otherwise, when you add multiple
to roundDown
, you'll get the wrong answer.
其次,您应该检查 numToRound 是否已经不是倍数。否则,当您添加multiple
到 时roundDown
,您会得到错误的答案。
Thirdly, your casts are wrong. You cast numToRound
to an integer, but it's already an integer. You need to cast to to double before the division, and back to int after the multiplication.
第三,你的演员阵容是错误的。您转换numToRound
为一个整数,但它已经是一个整数。您需要在除法之前转换为 double ,并在乘法之后返回 int 。
Lastly, what do you want for negative numbers? Rounding "up" can mean rounding to zero (rounding in the same direction as positive numbers), or away from zero (a "larger" negative number). Or, maybe you don't care.
最后,你想要什么负数?“向上”四舍五入可能意味着四舍五入到零(以与正数相同的方向四舍五入)或远离零(“更大”的负数)。或者,也许你不在乎。
Here's a version with the first three fixes, but I don't deal with the negative issue:
这是包含前三个修复程序的版本,但我不处理负面问题:
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);
}
回答by haneefmubarak
Round to Power of Two:
轮到二的幂:
Just in case anyone needs a solution for positive numbers rounded to the nearest multiple of a power of two (because that's how I ended up here):
以防万一有人需要将正数四舍五入到最接近的 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;
}
The input number will stay the same if it is already a multiple.
如果它已经是倍数,则输入数字将保持不变。
Here is the x86_64 output that GCC gives with -O2
or -Os
(9Sep2013 Build - godbolt GCC online):
这是 GCC 提供的 x86_64 输出-O2
或-Os
(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
Each C line of code corresponds perfectly with its line in the assembly: http://goo.gl/DZigfX
每行 C 代码都与它在程序集中的行完美对应:http: //goo.gl/DZigfX
Each of those instructions are extremely fast, so the function is extremely fast too. Since the code is so small and quick, it might be useful to inline
the function when using it.
这些指令中的每一条都非常快,因此该功能也非常快。由于代码又小又快,所以inline
在使用时可能对函数有用。
Credit:
信用: