2010-05-02 20 views
10

如果我有變量a,b,一個類型爲double的c,讓c:= a/b,並給出a和b的值爲7和10,那麼c的值爲0.7註冊爲小於0.70。另一方面,如果變量都是類型擴展的,那麼c的0.7值不會小於0.70。德爾福數學:爲什麼0.7 <0.70?

這似乎很奇怪。我缺少什麼信息?

+0

的http://stackoverflow.com/questions/1661273/java-floating-point-arithmetic – 2010-05-02 17:27:56

+10

可能重複這這是關於SO的最常見(最常見的)問題之一,與Delphi沒有什麼特別的關係,只是Comptuers存儲浮點數的方式。 – 2010-05-02 17:28:19

+1

不是說,這阻止了upvoted :) – 2010-05-02 17:35:07

回答

11

在二進制浮點數中沒有數學編號0.7的表示法。你的陳述計算在c最接近的double,根據你說的,我沒有檢查)略低於0.7。

顯然,在擴展精度中,最接近0.7的浮點數稍高於它。但是仍然沒有0.7的確切表示。二進制浮點沒有任何精度。作爲一個經驗法則,其最後一個非零十進制數不是5的非整數數字不能完全表示爲二進制浮點數(反之不正確:0.05不能完全表示)。

5

你錯過了This Thing

特別參見'準確度問題'一章。另見帕斯卡的回答。 爲了在不使用Extended類型的情況下修復代碼,您必須添加Math單元,並使用專門爲此設計的SameValue函數。

在您的案例中使用SameValue時,請務必使用不等於0的Epsilon值。

例如:

var 
    a, b, c: double; 


begin 
    a:=7; b:=10; 
    c:=a/b; 

    if SameValue(c, 0.70, 0.001) then 
    ShowMessage('Ok') 
    else 
    ShowMessage('Wrong!'); 
end; 

HTH

18

首先,它需要指出的是,在Delphi浮子文字是擴展類型。所以當你把一個double與一個literal相比較時,double可能會首先被「擴展」爲Extended,然後進行比較。 (編輯:這僅適用於32位應用程序,在64位應用程序中,ExtendedDouble的別名)

在此,將顯示所有ShowMessage。

procedure DoSomething; 
var 
    A, B : Double; 
begin 
    A := 7/10; 
    B := 0.7; //Here, we lower the precision of "0.7" to double 

    //Here, A is expanded to Extended... But it has already lost precision. This is (kind of) similar to doing Round(0.7) <> 0.7 
    if A <> 0.7 then 
    ShowMessage('Weird'); 

    if A = B then //Here it would work correctly. 
    ShowMessage('Ok...'); 

    //Still... the best way to go... 
    if SameValue(A, 0.7, 0.0001) then 
    ShowMessage('That will never fails you'); 
end; 

這裏有些文獻對你

What Every Computer Scientist Should Know About Floating-Point Arithmetic

+3

+ 1用於關於浮點運算的典型鏈接。 – 2010-05-02 18:18:19

+1

+1,並提及擴展與雙倍。 – 2010-05-03 08:27:08

+0

夥計。 :-) 你太棒了。 – 2010-12-09 00:44:42

8

它具有精度數字在你使用的兩種不同的浮點類型數量,做到了,而事實上,很多無論精確度如何,都無法準確表示數字。 (從純粹的數學方面:無理數超過理性)

以2/3爲例。它不能完全用十進制表示。有4位有效數字,它將表示爲0.6667。有8位有效數字,它將是0.66666667。 最後的7是綜合反映,如果有空間來保存下一個數字將是> 5。

0.6667大於0.66666667,因此計算機將評估2/3(4位數)> 2/3(8位數)。

你的.7和.70在雙倍和延長變量中也是如此。

要避免此特定問題,請嘗試在整個代碼中使用相同的數字類型。通常在處理浮點數時,有許多小事情需要注意。最重要的是不要編寫代碼來比較兩個浮點數是否相等 - 即使它們應該是相同的值,計算中有很多因素可以使它們最終變得非常微小。而不是比較平等,你需要測試兩個數字之間的差異是非常小的。差異有多小取決於你和你的計算性質,它通常被稱爲epsilon,取自微積分定理和證明。

+0

實際上,所有可計算的數字都可以完全表示:) – fishlips 2010-05-04 15:25:30

+1

我認爲這是一個合理的解釋,但我會補充說:「許多具有有理結束小數表示的數字沒有精確的終止(有理數)二進制浮點表示」。這一事實似乎使許多開發人員的注意無效。 – 2010-12-09 00:46:28