10

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

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;

结果:15.000000000000014211

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

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

4

5 回答 5

18

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

#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 次,即使使用这种方法也会显示累积的错误——这就是浮点数的工作方式。

于 2010-05-26T00:28:34.000 回答
15

为什么是这样?

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

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

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

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

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

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

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

于 2010-05-26T05:33:08.067 回答
8

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

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

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

于 2010-05-26T00:24:29.433 回答
1

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

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

于 2010-05-26T00:26:03.563 回答
-2

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

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

或者

http://speleotrove.com/decimal

于 2010-05-26T00:26:57.983 回答