2010-05-07 128 views
7

对不起,如果愚蠢但无法找到答案。C++数字截断错误

#include <iostream> 

using namespace std; 

int main() 
{ 
double a(0); 
double b(0.001); 
cout << a - 0.0 << endl; 
for (;a<1.0;a+=b); 
cout << a - 1.0 << endl; 
for (;a<10.0;a+=b); 
cout << a - 10.0 << endl; 
cout << a - 10.0-b << endl; 
return 0; 
} 

输出:
6.66134e-16
0.001
-1.03583e-13

试图与MSVC9,MSVC10,用Borland C++ 2010.它们在到达编译它结束约1e-13的误差。 只有1000,10000个增量有这么大的误差积累是否正常?

+3

http://docs.sun.com/source/806-3568/ncg_goldberg.html – Anycorn 2010-05-07 01:27:34

+0

http://home.comcast.net/~tom_forsyth/blog澄清。 wiki.html#[[A%20matter%20of%20precision]](不是我,heh) – 2010-05-07 01:51:12

回答

13

是的,这是正常的数值表示浮点错误。这与硬件必须接近大多数浮点数的事实有关,而不是完全存储它们。因此,你使用的编译器应该不重要。

What Every Computer Scientist Should Know About Floating-Point Arithmetic

+0

谢谢,我明白截断错误和所有其他废话。在数值方法上做了大量的理论工作,但我从来没有亲自检查过它,并且很惊讶地发现它有多大。 – Andrew 2010-05-07 01:35:42

+1

那么,一个double给你大约16个十进制数字的精度,这是正确的。当循环1000次时,精度可降至13位左右。 – WhirlWind 2010-05-07 01:39:57

+1

请注意,只有非理性(基数为2)的数字才会特别痛苦。如果你使用两个幂,你会没事的。例如。如果你的加法器是0.5,0.25,0.125,0.0255等,它们最终将*精确地加到*为1.0,因为这些基于2的值是0.1,0.01,0.001和0.0001。 – 2010-05-07 01:55:28

1

这与浮点数—他们是近似的,奇怪的事情在发生零(即,怪异的表述出现)的问题。因此,您认为理所当然的一些操作必须更加精细地处理。

当比较两个数字,你不能简单地说a == b因为一个可能是0和其他-1.03583e-13由于沿浮点运算精度损失应用于去ab。你必须选择一个任意的容差,像这样:fabs(a,b) < 1e-8

打印数字时,通常需要限制打印的位数。如果你使用printf,你可以说printf("%g\n", a);,它不会打印像-1.03583e-13的东西。我不知道是否有iostream类似于%g;在那儿?

2

这是使用你永远不应该做的浮点错误时为什么:

if(foo == 0.0){ 
    //code here 
} 

,而是做

bool checkFloat(float _input, float _compare, float _epsilon){ 
    return (_input + _epsilon > _compare) && (_input - _epsilon < _compare); 
} 
+1

在许多情况下检查零是正确的,因为它可以完全在硬件中表示,但当然这取决于你在做什么...从1开始,减去.1十次不会导致0,当然。 – 2010-05-07 01:53:05

+1

这是非常真实的,但在大多数情况下,这只是不好的做法。我喜欢小心谨慎。 – wheaties 2010-05-07 01:55:16

+0

在谨慎的一边犯错......有趣;)或者可能在epsilon的大小下犯错。 – WhirlWind 2010-05-07 01:59:27

2

想一想。每个操作都会引入轻微错误,但下一步操作会使用稍微错误的结果。给予足够的迭代,你会偏离真正的结果。如果您愿意,请以表格t0 = (t + y + e), t1 = (t0 + y +e)填写您的表达式,并用epsilon计算出术语。从他们的术语你可以估计近似误差。

还有第二个错误来源:在某些时候,您正在将相对较小且相对较大的数字结合起来。如果您记得机器精度的定义,在某些时候操作将会失去重要的位。

希望这有助于在外行人而言