1. 整數
例如十進制的 30
30/2 .......... 0
15/2 ............ 1
7/2 ............ 1
3/2 .............. 1
1/2 .............. 1
所以得到結果是 從下往上,倒着排 11110 就是二進制的 30
2. 小數
例如十進制的 0.125
0.125*2=0.25 ............. 0
0.25*2=0.5 ............. 0
0.5*2=1 ............. 1
所以得到結果是 從上往下,順着排 0.001 就是二進制的 0.125
3.為什么 0.1 + 0.2 !== 0.3 ?
因為 JS 采用了 IEEE 754 雙精度版本(64位), 只要采用了 IEEE 754 的語言都會有這個問題。
從上面我們看到,二進制的小數是怎么算的,而這種結果很可能會導致無限循環。
例如十進制的 0.1
0.1*2=0.2 .......... 0
0.2*2=0.4 .......... 0
0.4*2=0.8 .......... 0
0.8*2=1.6 .......... 1
0.6*2=1.2 .......... 1
0.2*2=0.4 .......... 0
。。。
所以得到結果是 從上往下,順着排 0.00011(0011不斷循環) 就是二進制的 0.1
因為我們不可能把 0.1 的無限循環都記錄下來,所以 0.1 在 JS 引擎里面被截取了前面的部分
因此 0.1 在 JS 引擎里面不再精確地表示 0.1 了。
同樣 0.2 也有或者這個問題,所以 2 個非精確的小數相加,也就得到一個非精確的小數了。
ps: 認真數了一下,JS 到小數點后第18位,就完全忽略了。
JS Number 類型的二進制組成
根據國際標准 IEEE 754,JavaScript 浮點數的64個二進制位,從最左邊開始,是這樣組成的。
- 第1位:符號位,
0
表示正數,1
表示負數 - 第2位到第12位(共11位):指數部分 (表示 2^−1022~2^1023)
- 第13位到第64位(共52位):小數部分(有效數字,可以到53位精度)
疑問1:為什么明明52位,為什么可以表示53位精度?
IEEE754規定小數部分第一位隱含為1,不寫,因為所有二進制第一個有效數字都是1。
所以加上省略的1位,精度位數是 53 bit
。所以在 0 ~ 2^53
內的整數都是有效數字,算上第1位符號位,就可以得到 -2^53 ~ 2^53 都是有效數字
。
疑問2:為什么 11 位指數位,負數方向只能表示到 2^-1022 ,不能表示到 2^-1024 呢?
無論如何浮點數都滿足最左邊是 1。這就有一個嚴重問題:0沒有辦法被表示,因此指數為 -1023 時表示 0。
還有一種情況就是 Infinity,這種情況當指數是 -1024 時,表示無窮大