r语言 - 使用C++中的"round-to-even"将双倍舍入到小数点后 n 位
r - Rounding doubles to n decimal points using "round-to-even" in C++
我想在C++中实现一个函数:
double round_to_even(double num, int decimal_places);
/* rounds the first argument to three decimal places
using round-to-even (unbiased rounding) */
它的行为与R中的四舍五入的工作方式相同,使用了一种称为四舍五五入、无偏四入或统计学家四舍五进的方法:https://stat.ethz.ch/R-manual/R-devel/library/base/html/Round.html最好的方法是通过R中的几个例子来说明这一点,其中decimal_place=3:
> round(0.1247,3) # rounding the first argument to three decimal places
[1] 0.125
> round(0.1244,3)
[1] 0.124
注意它的行为,当指定decimal_place右侧的数字大于5(此处等于7(时向上取整,当它小于5时截断(此处等于4(。然而,当指定decimal_place右侧的数字等于5(或在"中点"处(时,其行为如下:
> round(0.1255,3) # will round up
[1] 0.126
> round(.1275,3) # will round up
[1] 0.128
> round(0.1265,3) # will truncate
[1] 0.126
> round(0.1245,3) # will truncate
[1] 0.124
decimal_place左边的数字为奇数时取整,偶数时截断。
有没有一种简洁的方法来实现这一点,特别是在不将数字转换为字符的情况下?
编辑:这是我能想到的最好的:
double round_to_even(double number, int decimal_points)
/* rounds the first argument to three decimal places
using round-to-even (unbiased rounding) */
{
double num_left = number, num_right = number;
int digit_left, digit_right;
num_left *= pow(10, decimal_points + 1);
digit_left = fmod(num_left, 10);
if (digit_left == 5)
{
num_right *= pow(10, decimal_points);
digit_right = fmod(num_right, 10);
if (digit_right % 2 == 0) // if even
return floor(number * pow(10, decimal_points)) / pow(10, decimal_points);
else // otherwise it's odd
return ceil(number * pow(10, decimal_points)) / pow(10, decimal_points);
}
else { // standard round-to-nearest
return round(number * pow(10, decimal_points)) / pow(10, decimal_points);
}
}
我已经测试过了:
std::vector<double> test_vector({ 0.1247, 0.1244, 0.1255, 0.1275, 0.1265, 0.1245 });
std::vector<double> expected_values({ 0.125, 0.124, 0.126, 0.128, 0.126, 0.124 });
for (std::vector<double>::size_type i = 0; i < test_vector.size(); i++)
std::cout << "expected: " << expected_values[i] << "t got: " << round_to_even(test_vector[i], 3) << std::endl;
它给出以下输出:
expected: 0.125 got: 0.125
expected: 0.124 got: 0.124
expected: 0.126 got: 0.126
expected: 0.128 got: 0.128
expected: 0.126 got: 0.126
expected: 0.124 got: 0.124
double round(double d, int n) {
double last = d * pow(10, n + 1);
int last_dig = floor(last) % 10;
if (last_dig != 5)
return reg_round(d, n); //round as normal
double pre_last = d * pow(10, n);
int pre_last_dig = floor(pre_last) % 10;
if (pre_last_dig %2 == 0)
return floor(d,n); //last digit is even, floor.
else
return ceil(d,n); //last digit is odd, ceil.
}
假设CCD_ 1是正规圆。
我最近为了工作不得不研究这个问题,我研究了dtoa.c,但我试图使用的精简版本似乎在windows上有问题,这可能是我的错,但最终我自己实现了round,甚至也就是银行家舍入/统计学家舍入:
#include <math.h>
#include <stdio.h>
void bankerRound(double d, int decimals, char *buffer, int bufferLength) {
const auto powerTen = pow(10.0, decimals);
double intPart = 0;
double fractionPart = fabs(modf(d, &intPart));
double fractionRaised = fractionPart * powerTen;
double fractionRaisedAndRounded;
double fractionRaisedIntComponent = NAN;
if (modf(fractionRaised, &fractionRaisedIntComponent) == 0.5) {
if ((long) fractionRaisedIntComponent % 2 == 0) {
fractionRaisedAndRounded = floor(fractionRaised);
} else {
fractionRaisedAndRounded = ceil(fractionRaised);
}
} else {
fractionRaisedAndRounded = round(fractionRaised);
}
if (fractionRaisedAndRounded >= powerTen) {
fractionRaisedAndRounded -= powerTen;
intPart = intPart < 0 ? intPart - 1 : intPart + 1;
}
snprintf(buffer, static_cast<size_t>(bufferLength), "%.0lf.%0*.0lf", intPart, decimals, fractionRaisedAndRounded);
}
modf分离二重的整数分量和分数分量,这意味着我们不需要将二重提高到大幂,可能会溢出。然而,乘以分数可能会导致不准确,因为值不能准确地以2为基数表示,所以我只会在你只使用小数点后6位的情况下使用这个函数。否则,最好尝试使用dtoa.c或更新的Ryú算法。
相关文章:
- C++将浮点指针值舍入为小数位数
- Boost::posix_time::ptime舍入到给定的分钟数
- 浮点定向舍入和优化
- 为什么输出精度没有正确舍入?
- 使用设置精度时如何阻止数字向上舍入?
- 如何在使用 MPFR 时在提升多精度中设置舍入模式
- OpenCV 细分一致的 Rect2f 到 Rect2i 舍入
- C++ 中的舍入函数
- 舍入 QDecDouble 值,精度最多为两个字符
- 将大 int 转换为浮点数,而不舍入 c++
- 舍入错误检测
- 根据浮点符号对浮点进行舍入的最简单方法是什么
- 将整数舍入到另一个整数的最接近的倍数
- Sizeof 舍入到对齐方式,但编译器仍将对象放在剩余的字节中
- 避免将 Int 转换为双重类型转换舍入
- 浮点数学运算后舍入不一致
- 浮动到绳子而无需舍入
- C++长双精度格式而不舍入
- 使用设置精度在C++中舍入小数点时出现问题
- r语言 - 使用C++中的"round-to-even"将双倍舍入到小数点后 n 位