面試官瘋了嗎,問我爲什麼浮點數不精確?

很多人都知道,Java 中的浮點數並不精確,需要用 BigDecimal進行精確計算,但是,很少有人知道爲什麼浮點數不精確呢?不精確爲什麼還要用呢?本文就來展開分析一波;

我們知道,計算機的數字的存儲和運算都是通過二進制進行的,對於,十進制整數轉換爲二進制整數採用"除2取餘,逆序排列"法

具體做法是:

  • 用2整除十進制整數,可以得到一個商和餘數;
  • 再用2去除商,又會得到一個商和餘數,如此進行,直到商爲小於1時爲止
  • 然後把先得到的餘數作爲二進制數的低位有效位,後得到的餘數作爲二進制數的高位有效位,依次排列起來。

如,我們想要把127轉換成二進制,做法如下:

-w624

那麼,十進制小數轉換成二進制小數,又該如何計算呢?

十進制小數轉換成二進制小數採用"乘2取整,順序排列"法。

具體做法是:

  • 用2乘十進制小數,可以得到積
  • 將積的整數部分取出,再用2乘餘下的小數部分,又得到一個積
  • 再將積的整數部分取出,如此進行,直到積中的小數部分爲零,此時0或1爲二進制的最後一位。或者達到所要求的精度爲止。

如嘗試將0.625轉成二進制:

-w624

但是0.625是一個特列,用同樣的算法,請計算下0.1對應的二進制是多少:

-w624

我們發現,0.1的二進制表示中出現了無限循環的情況,也就是(0.1)10 = (0.000110011001100…)2

這種情況,計算機就沒辦法用二進制精確的表示0.1了。

所以,爲了解決部分小數無法使用二進制精確表示的問題,於是就有了IEEE 754規範。

IEEE二進制浮點數算術標準(IEEE 754)是20世紀80年代以來最廣泛使用的浮點數運算標準,爲許多CPU與浮點運算器所採用。

浮點數和小數並不是完全一樣的,計算機中小數的表示法,其實有定點和浮點兩種。因爲在位數相同的情況下,定點數的表示範圍要比浮點數小。所以在計算機科學中,使用浮點數來表示實數的近似值。

IEEE 754規定了四種表示浮點數值的方式:單精確度(32位)、雙精確度(64位)、延伸單精確度(43比特以上,很少使用)與延伸雙精確度(79比特以上,通常以80位實現)。

其中最常用的就是32位單精度浮點數和64位雙精度浮點數。

單精度浮點數在計算機存儲器中佔用4個字節(32 bits),利用“浮點”(浮動小數點)的方法,可以表示一個範圍很大的數值。

比起單精度浮點數,雙精度浮點數(double)使用 64 位(8字節) 來存儲一個浮點數。

IEEE並沒有解決小數無法精確表示的問題,只是提出了一種使用近似值表示小數的方式,並且引入了精度的概念。

一個浮點數a由兩個數m和e來表示:a = m × b^e。

在任意一個這樣的系統中,我們選擇一個基數b(記數系統的基)和精度p(即使用多少位來存儲)。m(即尾數)是形如±d.ddd...ddd的p位數(每一位是一個介於0到b-1之間的整數,包括0和b-1)。

如果m的第一位是非0整數,m稱作規格化的。有一些描述使用一個單獨的符號位(s 代表+或者-)來表示正負,這樣m必須是正的。e是指數。

最後,由於計算機中保存的小數其實是十進制的小數的近似值,並不是準確值,所以,千萬不要在代碼中使用浮點數來表示金額等重要的指標。

建議使用BigDecimal或者Long(單位爲分)來表示金額。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章