天天看點

js計算精度問題

在用js做計算的時候,經常會出現下面的這些問題:

0.1 + 0.2 = 0.30000000000000004
0.3 - 0.2 = 0.09999999999999998
20.123/100 = 0.201230000000000000000002
2.425*100 = 2.424999999999997           

IEEE 754 64 位浮點類型

IEEE 754

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

該标準的全稱為IEEE二進制浮點數算術标準(ANSI/IEEE Std 754-1985),又稱IEC 60559:1989,微處理器系統的二進制浮點數算術(本來的編号是IEC 559:1989)。

單精度浮點數

單精度浮點數格式是一種資料類型,在計算機存儲器中占用 4 個位元(32 bits),利用“浮點”(浮動小數點)的方法,可以表示一個範圍很大的數值。

在 IEEE 754-2008 的定義中,32-bit base 2 格式被正式稱為 binary32 格式。這種格式在 IEEE 754-1985 被定義為 single,即單精度。需要注意的是,在更早的一些計算機系統中,也存在着其他 4 位元組的浮點數格式。

定義

第 1 位表示正負,中間 8 位表示指數,後 23 位儲存有效數位(有效數位是 24 位)。

中間八位共可表示 28=256 個數,指數可以是二補碼;或 0 到 255,0 到 126 代表-127 到-1,127 代表零,128-255 代表 1-128。

有效數位最左手邊的 1 并不會儲存,因為它一定存在(二進制的第一個有效數字必定是 1)。換言之,有效數位是 24 位,實際儲存 23 位。

js計算精度問題

雙精度浮點數

雙精度浮點數(double)是計算機使用的一種資料類型。比起單精度浮點數,雙精度浮點數(double)使用 64 位(8 位元組) 來存儲一個浮點數。 它可以表示十進位制的 15 或 16 位有效數字,其可以表示的數字的絕對值範圍大約是 [2.23e-308,1.79e308]

和單精度類似,第 1 位表示正負,後 11 位為指數位,最後 52 位表示精确度(有效位數是 53 位)。

js計算精度問題

0.1/0.2的二進制位

(0.1).toString(2) === "0.000 110011001100110011001100110011001100110011001100110 1“

(0.2).toString(2) === "0.00 1100110011001100110011001100110011001100110011001101"

(0.30000000000000004).toString(2) === "0.0100110011001100110011001100110011001100110011001101"

(0.3).toString(2) === "0.010011001100110011001100110011001100110011001100110011"

是以最終 0.1 用二進制表示是 0.0001 1001 1001 1001 ...,但是我們看上面 (0.1).toString() 最後的六位 001101,正常循環應該是 001100,是以截斷之後,0.1 二進制表示的值變大了!!!。0.2 轉換為二進制表示截斷之後也變大了。

通過對比 0.1、0.2 及它們的和的二進制表示,可以發現字元串的長度變化了,但是精确度卻沒有變化,也就是從 1 開始到最後的字元串長度都是 52。

0.1 + 0.2 本來應該是長度在為 57,但是由于無法表示這樣一個數,重新從 1 開始的數字開始計數,會截斷最後的三個數字 (最後精确度為 52 或者 53 )

繼續閱讀