c++ - 以溢出安全的方式用 N 个有效的十进制数字舍入 double

标签 c++ rounding

我想要一个溢出安全函数,像std::round一样舍入double,此外它还可以处理有效小数数字。

现在

round(-17.747, 2) -> -17.75
round(-9.97729, 2) -> -9.98
round(-5.62448, 2) -> -5.62
round(std::numeric_limits<double>::max(), 10) ...

我的第一次尝试是

double round(double value, int precision)
{
    double factor=pow(10.0, precision);
    return floor(value*factor+0.5)/factor;
}

但这很容易溢出。

假设 IEEE,可以减少溢出的可能性,就像这样。

double round(double value, int precision)
{
    // assuming IEEE 754 with 64 bit representation
    // the number of significant digits varies between 15 and 17

    precision=std::min(17, precision);
    double factor=pow(10.0, precision);
    return floor(value*factor+0.5)/factor;
}

但这仍然会溢出。

即使是这种性能灾难也不起作用。

double round(double value, int precision)
{
    std::stringstream ss;
    ss << std::setprecision(precision) << value;
    std::string::size_type sz;
    return std::stod(ss.str(), &sz);
}
round(std::numeric_limits<double>::max(), 2.0) // throws std::out_of_range

注意:

  • 我知道 setprecision,但我需要四舍五入不只是为了显示目的。所以这不是解决方案。
  • 不喜欢这里的帖子How to round a number to n decimal places in Java ,我的问题尤其是关于溢出安全和 C++(上面主题中的答案是特定于 Java 的或者不处理溢出)

最佳答案

我没有对这段代码进行大量测试:

/* expects x in (-1, 1) */
double round_precision2(double x, int precision2) {
    double iptr, factor = std::exp2(precision2);
    double y = (x < 0) ? -x : x;
    std::modf(y * factor + .5, &iptr);
    return iptr/factor * ((x < 0) ? -1 : 1);
}

double round_precision(double x, int precision) {
    int bits = precision * M_LN10 / M_LN2;
            /* std::log2(std::pow(10., precision)); */
    double iptr, frac = std::modf(x, &iptr);
    return iptr + round_precision2(frac, bits);
}

这个想法是通过只对数字的小数部分进行操作来避免溢出。

我们计算二进制位数以达到所需的精度。您应该能够根据您在问题中描述的限制来限制它们。 接下来,我们提取数字的小数部分和整数部分。 然后我们将整数部分加回四舍五入的小数部分。

为了计算四舍五入的小数部分,我们计算二进制因子。然后我们提取小数部分乘以该因数得到的四舍五入数的整数部分。然后我们通过将整数部分除以该因子来返回分数。

关于c++ - 以溢出安全的方式用 N 个有效的十进制数字舍入 double ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60503818/

相关文章:

java - 文件格式规范中的空终止字符短语

c++ - 稍后添加 initializer_list 构造函数时,使用大括号初始化语法会改变构造行为吗?

sql - sql server 中的舍入值

postgresql - 如何在自动四舍五入的除法 PostgreSQL 中添加小数点

MATLAB - 楼层问题

c - 用 c 舍入

c++ - 强制 cpp_dec_float 向下舍入

c++ - 我正在尝试使用类创建具有已指定的最大大小的数组,但似乎未创建该数组

c++ - 如何在评论或引用时忽略分隔符

c++ - 使用 boost 的 LU 求解器但避免计算逆矩阵?