2010-05-26 135 views
3

可能重复:
Floating point inaccuracy examplesC++浮点精度

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'比它应该小。 但是,如果我们采取'一个'50次 - 结果会比它应该更大。

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

+4

去看看吧。浮点问题需要仔细研究,以免发生危险错误。 – Artelius 2010-05-26 00:26:12

+0

有精确的值使用整数来代替(或一些bignum lib)const int acc = 100; int tmp,a = 30/acc,b = 0; for(char i = 1; i <= 50; i ++)b = b + a; std :: cout << int(b/acc)<<“。”; TMP = B%ACC; if(tmp <10)std :: cout <<“0”; std :: cout << int(tmp);为了加快速度,你可以使用2的幂乘以所以*,/,%转换为<<,>>和 – Spektre 2013-08-20 13:07:12

回答

14

为了得到正确的结果,不要设置的精度大于此数字类型的可用范围:

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

+4

对于numeric_limits,+1确切地说是不够的,因为它们应该是。 – 2010-05-26 00:47:47

5

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

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

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

+2

我认为OP的关键答案是“你无法使用浮点得到正确的结果”。 :) – 2010-05-26 01:20:51

+3

你会得到正确的结果。可以肯定的是,不是你期待的结果。 – MSalters 2010-05-26 07:15:07

1

这并不是说它变得更大或更小,它只是在一个二进制浮点数内存储“0.3”作为一个确切值是不可能的。

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

+0

0.3或0.3333 ....? – 2016-04-26 12:50:10

8

这是为什么?

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

请记住,对于设计了浮点的应用程序,这不是一个问题,您无法准确表示0.3。浮点被设计为用于:

  • 物理测量,这往往是测量到只有4 SIG无花果和从未超过15
  • 超越功能,如对数和三角函数,这无论如何只是近似。

对于哪些二进制十进制转换与其他错误来源几乎无关。

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

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

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

+0

也许你可以添加到第一段的末尾:“...因为0.3的二进制表示的无限序列在某个点被切断,因为无限值不能存储在计算机上”。 – josch 2016-08-18 05:46:52