先拋出幾個問題
git
接下來就以這三個問題爲目的來梳理一下前因後果。
github
首先在開始以前須要瞭解一下JavaScript的number類型在計算機中是如何存儲的,這也是一切問題的基礎。JavaScript的數字都是number類型的,不論是整數仍是浮點數都以IEEE754雙精度的格式存儲在計算機中,什麼是雙精度呢?就是以64個bit位來存儲,具體的存儲格式是:
瀏覽器
分別是1個符號位+11個指數位+52個尾數位
安全
舉個例子,若是是5.5這個數字的話,則計算過程是這樣的:
5.5 轉二進制 =====> 101.1 科學計數法 =====> 1.011*2^2
存入計算機:
符號位:0
指數位:2 加1023 =====> 1025 轉二進制 =====> 10000000001
尾數位:1.011 隱去小數點左邊的1 =====> 011
存入計算機,以下圖,截圖來自IEEE754可視化,感興趣能夠把玩一下
測試
在瀏覽器控制檯能夠測試一下結果:
debug
0.1 轉二進制 =====> 0.0001100110011001100...(1100循環)
轉科學計數法 =====> 1.100110011...(1100循環) *2^-4
數據是無限循環的,可是可供使用的尾數位倒是有限的,只有52位可使用,因此在第53位會被捨去而且進位
最終在計算機中存儲以下圖:
3d
相似的0.2在計算機中的存儲以下圖:
orm
因此最終的計算就是:
cdn
0.00011001100110011001100110011001100110011001100110011010 + 0.0011001100110011001100110011001100110011001100110011010 = 0.0100110011001100110011001100110011001100110011001100111
能夠看出來其實0.1是截斷了一部分精度後獲得的結果,那麼這個問題就能夠轉化爲:雙精度浮點數是按什麼規則來截斷的呢?
blog
在雙精度浮點數的英文wiki中能夠找到中能夠找到這麼一段話:
大意是:若是一個 IEEE 754 的雙精度浮點數被轉成至少含17位有效數字的十進制數字字符串,當這個字符串轉回雙精度浮點數時,必需要跟原來的數相同;換句話說,若是一個雙精度的浮點數轉爲十進制的數字時,只要它轉回來的雙精度浮點數不變,精度取最短的那個就行。
很明顯1.005只是一個被截斷後的數字,它的雙精度浮點數表明的20位精度的數字是1.0049999999999998934,因此進行保留2位的四捨五入時,2位後的數字會被所有捨去。
爲何最大安全整數是2^53-1?前面說到了JavaScript浮點數存儲是52位尾數位,可是由於科學計數法小數點左側的1會在存儲時省去,因此52位尾數+省去的1位=53個可表示的位數。
2^53 轉二進制 =====> 100000000000000000000000000000000000000000000000000000(53個0)
轉爲科學計數法 =====> 1.00000000000000000000000000000000000000000000000000000(53個0)*2^53
存入計算機 =====> 尾數位只有52位因此截掉末尾的0只能存52個0
2^53+1 轉二進制 =====> 100000000000000000000000000000000000000000000000000001(52個0)
轉爲科學計數法 =====> 1.00000000000000000000000000000000000000000000000000001(52個0)
存入計算機 =====> 尾數位只有52位因此截掉末尾的1只能存52個0