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


很多人都知道,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(單位為分)來表示金額。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM