2010-05-07 200 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計算出術語。從他們的術語你可以估計近似誤差。

還有第二個錯誤來源:在某些時候,您正在將相對較小且相對較大的數字結合起來。如果您記得機器精度的定義,在某些時候操作將會失去重要的位。

希望這有助於在外行人而言