《程序世界》筆記6 整數與浮點小數(下)浮點小數你真的懂嗎

計算機中關於數字的一切問題的核心:計算機中用二進制來表示十進制的整數和浮點小數。

——藍薩節


為什麼叫浮點小數:

為何叫浮點數呢?是指小數點的位置可以移動。為什麼需要移動呢,它與計算機中數的表示方法有著密切的關係。

計算機本來只處理整數,事實上整數也是二進制的比特串。所以,必須要用某種方法,將含有小數部分的數變成二進制的比特串(編碼)

可以考慮用幾種方法將小數編碼成二進制。具代表性的方法有兩種:

  • 一是抬高小數進行整數化;

  • 二是使用科學計數法來表示。

進行整數化使用不廣泛,其優點是速度高,其缺點在可能造成浪費,小數位數固定。

因此一般用科學技術法表示。但計算機是用二進制,而不是用十進制來表示數,所以實際上這個數在內部不是以2.5和104來記錄的,必須變為二進制的比特串。變為比特串的方式有多種。廣泛採用的被稱作IEEE754方式。

《程序世界》筆記6 整數與浮點小數(下)浮點小數你真的懂嗎

f稱為尾數部分(mantissa),e稱為指數部分(exponent)。雙精度中,指數部分有11位,可以表示+1023~-1024,也就是可以表示2的1023次方。

尾數部分有52位。IEEE754規定,尾數部分的首位始終歸一化3為1,所以首位始終省略4,實質有效數字為53位。

所謂歸一化就是將尾數部分變成大於等於1,小於2的數。比如想表示48,可以用3×2^4表示,但必須寫成1.5×2^5的形式。

科學計數法表示浮點小數的問題:

  1. 小數不能完全表示:

除了與整數一樣有表示範圍的限制外,小數還有更復雜的情況,他們是

  • 除不盡的小樹無法完全表示

  • 十進制可以除盡的數二進制是除不盡的。

比如看下面一個程序:

《程序世界》筆記6 整數與浮點小數(下)浮點小數你真的懂嗎

我們看到0.1加10次不等於1.0,這是因為0.1在現實中是一個精確的數,但在計算機中用二進制表示的時候,只能用一個近似值來表示,我們看到加了十次後,誤差有1.110223e-16那麼大。這就造成了浮點數有誤差。我們關於浮點數有幾條鐵律。

關於使用浮點數的幾條鐵律:

鐵則一,兩個浮點數不能用==進行比較。如果有進行比較的必要,判斷條件中兩個數的差要寫得足夠小。這個數在Ruby中是Float::EPSILON,其值為2.22044604925031e-16。

鐵則二:減少運算次數。比如例子中乘以10,就比加十個0.1誤差小。

鐵則三:為了避免信息丟失,需要在計算順序方面想辦法,最基本的是要避免特大數和特小數之間的運算。

鐵則四:對於浮點小數,結合法不成立。因為結合法會擴大誤差。

浮點數運算的陷阱可以歸結為兩個原因:一是能夠表示的精度有限,二是以二進制表示。

解決浮點數誤差的兩個方法:

ruby語言中提供了BigDecimal類和能表示分數的Rational類。

IEEE754還定義了幾個特別的“數”

無限大:用來表示溢出錯誤。

零:零有符號,有正負之分。

NaN:not a number 表示非數,比如0/0,為了表示未定義的結果錯誤。


分享到:


相關文章: