2011-10-27 48 views
1

我計算Matlab的這個簡單的總和:Matlab的精度:簡單的減法是不爲零

2*0.04-0.5*0.4^2 = -1.387778780781446e-017 

但結果不是零。我能做什麼?

+0

類似的問題:[爲什麼24.0000不等於24.0000在MATLAB?](http://stackoverflow.com/questions/686439/why-is-24-0000-not-equal-to-24-0000 -in-matlab) – Amro

+0

也是一個更爲明顯的例子:'0.3 - 0.1 * 3'給出了'5.5511e-017'。 – Amro

+0

閱讀'eps'。 –

回答

4

Aabaz和Jim Clay對發生了什麼事有很好的解釋。

經常出現的情況是,並非精確計算2 * 0.04 - 0.5 * 0.4^2的值,您真正需要的是檢查2 * 0.04和0.5 * 0.4^2是否相差小到足以達到相關的數值精度。如果是這樣的話,而不是檢查是否2*0.04 - 0.5*0.4^2 == 0,可以檢查是否abs(2*0.04 - 0.5*0.4^2) < thresh。這裏thresh可以是一些任意的小數字,也可以是eps這個表達式,它提供了你正在使用的數字類型的精度。

編輯: 感謝Jim和Tal提出的改進建議。改變以比較差異的絕對值與閾值,而不是差異。

+2

好點。我會做的一個變化就是你需要將差值的絕對值與「thresh」進行比較。 –

1

我不知道它是否適用於您的問題,但通常最簡單的解決方案是擴展您的數據。

例如:

a=0.04; 
b=0.2; 
a-0.2*b 
ans=-6.9389e-018 
c=a/min(abs([a b])); 
d=b/min(abs([a b])); 
c-0.2*d 
ans=0 

編輯:當然,我不是故意要給出一個通用的解決方案,這些類型的問題,但它仍然是一個很好的做法,可以讓你避免的幾個問題數值計算(曲線擬合等)。請參閱Jim Clay的回答,解釋您遇到這些問題的原因。

+0

這是否總是工作,或者只是一些時間? –

+0

我真的不知道,但它肯定會在正確的方向去解決這類問題。 – Aabaz

+0

是否有這個原因,或者它只是在本例中碰巧做「正確」事情的臨時代碼? –

1

你所看到的是quantization error。 Matlab使用雙精度來表示數字,雖然它們具有很高的精度,但它們仍然無法表示所有實數,因爲有無數個實數。我不確定阿巴茲的詭計,但總的來說,我會說沒有什麼可以做的,除了可能將您的輸入按摩爲雙倍數字。

1

我很確定這是一個老問題浮點精度問題。

你需要1e-17精度嗎?這僅僅是想要'漂亮'的輸出嗎? 在這種情況下,您可以使用格式化的sprintf來顯示所需的有效數字的數量。

認識到這不是一個matlab問題,而是數字如何用二進制表示的一個基本限制。

爲了好玩,制定出什麼1.1處於二進制...

一些參考: http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems http://www.mathworks.com/support/tech-notes/1100/1108.html

2

Matlab使用雙精度浮點數來存儲實數。這些數字的格式爲m*2^e,其中m2^522^53尾數)之間的整數,而e是指數。如果它是這種形式,我們稱一個數字爲一個浮點數。

計算中使用的所有數字都必須是浮點數。通常,這可以完全按照您的表達式中的20.5完成。但對於其他數字,尤其是大多數帶小數點後數字的數字,這是不可能的,並且必須使用近似值。在這種情況下發生的情況是數字四捨五入到最接近的浮點數。

所以,只要你喜歡寫東西在Matlab 0.04,你其實是在說:「給我的浮點數最接近0.04在你的表達,有2個數字,需要近似: 0.040.4

此外,像加法和乘法的浮點數運算的精確結果可能不是一個浮點數,雖然它始終是形式m*2^e的尾數可能太大。所以,由於四捨五入的結果,你會得到一個額外的錯誤。

在一天結束時,像你這樣簡單的表達式將會大約是操作數大小的2^-52倍,或者大約10^-17。

總結:你的表達式的值不爲零的原因有兩方面:

  1. 一些數字你開始用不同(近似值)提供給您確切的數字。
  2. 中間結果也可能是精確結果的近似值。