2017-02-17 46 views

回答

8

Double確實更精確。是的,您應該瞭解浮點表示的一般情況:您必須非常小心使用它們! ==通常不太可能有用。您通常會想要使用更專用的函數比較浮點表示,或者至少檢查表達式是否位於某個範圍內,而不是根據內置近似值確定是否具有特定值。

13

實現的第一件事是,當你進入0.1::Double和ghci的打印0.1回來,這只是一個「假象」

Prelude Data.Ratio> 0.1::Double 
0.1 

爲什麼是幻覺?因爲0.1實際上不能精確表示爲浮點數!對於FloatDouble都是如此。注意:

Prelude Data.Ratio> toRational (0.1::Float) 
13421773 % 134217728 
Prelude Data.Ratio> toRational (0.1::Double) 
3602879701896397 % 36028797018963968 

所以,在現實中,這些數字的確是「接近」實際的實數0.1,但也恰恰是0.1。他們有多接近?讓我們來看看:

Prelude Data.Ratio> toRational (0.1::Float) - (1%10) 
1 % 671088640 
Prelude Data.Ratio> toRational (0.1::Double) - (1%10) 
1 % 180143985094819840 

正如你看到的,Double確實是很多比Float更精確;作爲Double0.1的表示與實際實數0.1之間的差異要小得多。但都不是確切的。

因此,確實Double的添加更加精確,應該優於Float版本。你看到的令人混淆的平等只不過是四捨五入的奇怪效果罷了。 ==的結果應該是而不是在浮點土地上值得信賴。實際上,有很多浮點數x,使得x == x + 1成立。這裏有一個例子:

Prelude> let x = -2.1474836e9::Float 
Prelude> x == x + 1 
True 

浮點表示很好看的是經典的What Every Computer Scientist Should Know about Floating-Point Arithmetic,這也解釋了許多浮點運算的這些古怪的問題。

另請注意,此行爲對於Haskell並不是唯一的。任何使用IEEE754 Floating-point arithmetic的語言都會採用這種方式,這是現代微處理器實現的標準。

+1

我個人儘量避免使用術語「浮點數」。當你開始看數學時,浮點數表示看起來並不像數字。 「Int」和「Word」等類型當然被用作「Integer」和「Natural」的近似值,但它們本身就是完美守法的交換環。另一方面,浮點表示實際上沒有好的性質:加法和乘法都不是聯合的,乘法不會在加法上分佈。 – dfeuer