C++浮点精度

Dav*_*nel 7 c c++ floating-point precision floating-accuracy

可能重复:
浮点不准确示例

double a = 0.3;
std::cout.precision(20);
std::cout << a << std::endl;
Run Code Online (Sandbox Code Playgroud)

结果: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;
Run Code Online (Sandbox Code Playgroud)

结果:15.000000000000014211

所以..'a'比它应该小.但是,如果我们采取'a'50次 - 结果会比它应该更大.

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

Cub*_*bbi 16

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

#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;
}
Run Code Online (Sandbox Code Playgroud)

虽然如果该循环运行5000次迭代而不是50次,即使采用这种方法,累积的错误也会出现 - 它只是浮点数的工作原理.

  • 对于numeric_limits,+1肯定是不够的,因为它们应该是已知的. (5认同)

dan*_*n04 11

为什么是这样?

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

请记住,对于设计浮点的应用程序,不能完全代表0.3的问题.浮点设计用于:

  • 物理测量,通常仅测量4 sig figs,从不测量超过15.
  • 超越函数,如对数和trig函数,无论如何都是近似的.

对于哪些二进制十进制转换与其他错误源相比几乎无关紧要.

现在,如果你正在编写财务软件,其中0.30 美元的价格恰好是 0.30美元,那就不同了.有针对这种情况设计的十进制算术类.

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

将精度限制为15位有效数字通常足以隐藏"噪音"数字.除非您确实需要一个确切的答案,否则这通常是最好的方法.


SLa*_*aks 7

计算机以二进制形式存储浮点数,而非十进制数.

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

如果添加许多浮点数,这些微小的差异会加起来,并且会得到意想不到的结果.

  • 你得到了正确的结果.不可否认,不是你期望的结果. (3认同)
  • 我认为OP的关键答案是,"你无法使用浮点获得正确的结果." :) (2认同)