【问题标题】:C++ floating point precision [duplicate]C ++浮点精度[重复]
【发布时间】:2011-02-23 23:08:06
【问题描述】:

可能重复:
Floating point inaccuracy examples

double a = 0.3;
std::cout.precision(20);
std::cout << a << std::endl;

结果:0.2999999999999999889

double a, b;
a = 0.3;
b = 0;
for (char i = 1; i <= 50; i++) {
  b = b + a;
};
std::cout.precision(20);
std::cout << b << std::endl;

结果:1​​5.000000000000014211

所以.. 'a' 比它应该的要小。 但是如果我们取 'a' 50 次 - 结果会比它应该的要大。

这是为什么? 在这种情况下如何得到正确的结果?

【问题讨论】:

  • 去阅读它。浮点问题需要仔细研究,以免犯危险的错误。
  • 要获得精确值,请使用整数(或一些 bignum 库) const int acc=100; int tmp,a=30/acc,b=0; for (char i=1;i>,&

标签: c++ c floating-point precision floating-accuracy


【解决方案1】:

计算机以二进制而不是十进制存储浮点数。

许多在十进制中看起来很普通的数字,例如 0.3,在二进制中没有有限长度的精确表示。
因此,编译器会选择具有精确二进制表示的最接近的数字,就像您为 1⁄3 编写 0.33333 一样。

如果您将许多浮点数相加,这些微小的差异加起来,您会得到意想不到的结果。

【讨论】:

  • 我认为 OP 的关键答案是,“你不能使用浮点得到正确的结果。” :)
  • 你得到了正确的结果。诚然,这不是您期望的结果。
【解决方案2】:

并不是它的大小,只是物理上不可能将“0.3”存储为二进制浮点数中的精确值。

获得“正确”结果的方法是不显示小数点后 20 位。

【讨论】:

    【解决方案3】:

    要获得“正确”的结果,请尝试

    来自维基百科的任意精度算术库列表: http://en.wikipedia.org/wiki/Arbitrary-precision

    http://speleotrove.com/decimal

    【讨论】:

    • 对于 OP 而言,十进制和任意精度的算术很可能是不必要的。
    【解决方案4】:

    要获得正确的结果,请不要设置大于此数字类型可用的精度:

    #include <iostream>
    #include <limits>
    int main()
    {
            double a = 0.3;
            std::cout.precision(std::numeric_limits<double>::digits10);
            std::cout << a << std::endl;
            double b = 0;
            for (char i = 1; i <= 50; i++) {
                      b = b + a;
            };
            std::cout.precision(std::numeric_limits<double>::digits10);
            std::cout << b << std::endl;
    }
    

    尽管如果该循环运行 5000 次而不是 50 次迭代,即使使用这种方法也会显示累积的错误 - 这就是浮点数的工作原理。

    【讨论】:

    • numeric_limits 的 +1 显然还不够为人所知。
    【解决方案5】:

    这是为什么?

    因为浮点数以二进制形式存储,其中 0.3 是 0.01001100110011001... 重复就像 1/3 是 0.333333... 以十进制重复。当你写 0.3 时,你实际上得到了 0.299999999999999988897769753748434595763683319091796875(四舍五入到 53 位有效数字的无限二进制表示)。

    请记住,对于为其设计浮点的应用程序,不能准确表示 0.3 不是问题。浮点数设计用于:

    • 物理测量,通常仅测量到 4 sig figs,从不超过 15。
    • 超越函数,例如对数和三角函数,无论如何只能近似。

    与其他错误来源相比,二进制-十进制转换几乎无关紧要。

    现在,如果您正在编写财务软件,0.30 美元意味着正好 0.30 美元,情况就不同了。有针对这种情况设计的十进制算术类。

    在这种情况下如何得到正确的结果?

    将精度限制为 15 个有效数字通常足以隐藏“噪声”数字。除非您确实需要一个准确的答案,否则这通常是最好的方法。

    【讨论】:

    • 也许您可以在第一段的末尾添加:“...因为 0.3 的二进制表示的无限级数在某些时候被切断,因为无限值不能存储在计算机上” .
    猜你喜欢
    • 2021-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-13
    • 2021-02-11
    相关资源
    最近更新 更多