【问题标题】:Incorrect rounding on gcc and Ubuntugcc 和 Ubuntu 上的舍入不正确
【发布时间】:2021-01-24 03:24:36
【问题描述】:

我目前正在将一些代码从 Windows 移植到 Linux (Ubuntu),从 MS VS2008 编译器移植到 GCC。

问题是下面的代码有不同的结果:

double            d = 19.53125;
std::cout.precision(4);
std::cout.setf(std::ios::fixed);

std::cout << d << std::endl;

Windows output: 19.5313
Linux output: 19.5312

如果我将精度设置为 5,则输出是相同的。

我预计 19.53125 将四舍五入为 19.5313。

有什么建议可以让我获得所需的舍入行为吗?

注意:Windows 代码在 Windows 10 笔记本电脑上本地运行,而 Linux 代码在 64 位 Ubuntu 18.04 LTS 虚拟机中运行。

【问题讨论】:

  • “我怎样才能获得所需的舍入行为?” --> 你还没有说明首选哪个输出。
  • 我希望 0.5 是向上取整而不是向下取整。
  • 我怀疑舍入例程使用区域设置。当 Windows 从当前环境中检索本地时,Linux 是否使用“C”本地?注意:只是猜测。
  • 我怀疑这回答了这个问题:stackoverflow.com/q/24120888/14065 基本上 C++ stackoverflow.com/a/24120966/14065 说它的实现定义了如何四舍五入和引用标准。

标签: c++ gcc visual-c++ double rounding-error


【解决方案1】:

这让我大开眼界。感谢所有的链接。 由于我无法找到一种方法来影响 printf 函数中的舍入行为,因此我没有看到其他解决方案来使用数学舍入函数。

以下解决方案仍然适用于我:

double         d = 19.53125;
int precision  p = 4;
double         factor = pow(10.0, p);
std::cout.precision(p);
std::cout.setf(std::ios::fixed);

std::cout << round(d * factor) / factor << std::endl;

Windows output: 19.5313
Linux output: 19.5313

链接:

  1. https://www.exploringbinary.com/inconsistent-rounding-of-printed-floating-point-numbers/
  2. Why printf round floating point numbers?

【讨论】:

    【解决方案2】:

    Bankers Rounding 是一种将数量四舍五入为整数的算法,其中与两个最接近的整数等距的数字被四舍五入为最接近的偶数。因此,0.5 向下舍入为 0; 1.5 舍入到 2。

    GCC C++ 标准库应用银行家四舍五入。 19.53125 -> 19.5312,因为 2 是最近的偶数。

    关于 C 的其他信息,但 C++ 尊重 C 舍入:C++ Rounding behavior consistency for ties with sprintf

    【讨论】:

    • 我试过了,在这种情况下 19.53135 应该变成 19.5314 但它也向下舍入到 19.5313。
    • 因为double中存储的实际值是19.53134918212890625。 Double 不能包含确切的值 19.53135。
    • 我可以理解,但是为什么调试器显示的是nice的数字而不是long的数字?
    • 尝试(gdb) printf "%1.20f\n", d查看该点后的20位数字。
    • 看起来我把这个数字算作浮点数,你的数字是正确的双精度数。在任何情况下,你都会得到 4 来代替 5。
    猜你喜欢
    • 2014-03-08
    • 2012-03-07
    • 1970-01-01
    • 2011-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-06
    相关资源
    最近更新 更多