- 爲何 0.1 + 0.2 !== 0.3?
- 爲何 Number.MAX_SAFE_INTEGER 值爲 Math.pow(2, 53) - 1?
- 爲何 Math.pow(2, 53) === Math.pow(2, 53) + 1 ?
- 爲何 Number.MAX_VALUE = 1.7976931348623157e+308 ?
- 爲何 1.005.toFixed(2) = 1.00 ?
下圖是單精度格式 git
對於單精度浮點數,採用32位存儲,最高的1位是符號位s,接着的8位是指數E(-126 ~ 127),剩下的23位爲有效數字尾數M。爲何E(雙精度)範圍是:-1022 ~ 1023 ?github
// E 的範圍
E = 0 二進制表示: 0 1111 1111 11 => 2^10 -1 = 1023
E 最大二進制表示(不能全爲1):1 1111 1111 10 => 2^11 - 2 = 2046
E 最小二進制表示(不能全爲0): 0 0000 0000 01 => 2^0 = 1
則E的範圍(1-1023)<= E (2046 - 1023)
複製代碼
1.xxx * 2^e
(這是一個規格化的表示),十進制浮點數轉二進制, eg:
bash
0.125
x 2 ----
----------------- |
0.25 0 |
x 2 |
----------------- |
0.5 0 |
x 2 |
----------------- |
1.0 1 ↓
複製代碼
13.125, 整數部分13 => 1101, 小數部分 0.125 => 0.001函數
13.125 => 1101.001 => 1.101001 * 2^3(存儲時,小數點前的1省略了,節省空間)
// 以上S=0; E=3(二進制表示爲:10000000010); M=101001,
則二進制表示爲:
0 10000000010 1010010000000000000000...
- ----------- -------------------------
s E(1023+3) M,52位長度
複製代碼
0.1 轉化位二進制: 0.0001100110011(0011循環) => 1.100110011(0011)*2^-4
0.2 轉化位二進制: 0.001100110011(0011循環) => 1.100110011(0011)*2^-3spa
a. 多餘位 <= 011...11, 捨去。
b. 多餘位 = 100...00, 判斷尾數的最低有效位的值,若爲0則直接捨去,若爲1則再加1。
c. 多餘位 >= 100...01, 進1。code
0.1 => 0.1100110011001100110011001100110011001100110011001100[1100110011...] => 進1 => 0.1100110011001100110011001100110011001100110011001101
0.2 => 1.1001100110011001100110011001100110011001100110011001[100110011...] => 進1 => 0.1100110011001100110011001100110011001100110011001110
0.1100110011001100110011001100110011001100110011001101 * 2^-3
+ 1.1100110011001100110011001100110011001100110011001110 * 2^-3
----------------------------------------------------------
10.0110011001100110011001100110011001100110011001100111 * 2^-3
=> 1.00110011001100110011001100110011001100110011001100111 * 2^-2
=> 1.0011001100110011001100110011001100110011001100110100 * 2^-2(因爲尾數只能52位,就近舍入)
轉化爲10進制
0.3000000000000000444089209850062616169452667236328125
=> 0.30000000000000004
複製代碼
- (2^53, 2^54) 之間的數會兩個選一個,只能精確表示偶數
- (2^54, 2^55) 之間的數會四個選一個,只能精確表示4個倍數
- ... 依次跳過更多2的倍數
Math.pow(2, 53) + 3 === Math.pow(2, 53) + 5 // true
Math.pow(2, 54) === Math.pow(2, 54) + 1 // true
Math.pow(2, 54) === Math.pow(2, 54) + 2 // true
複製代碼
Math.pow(2, 1024) // Infinity
Math.pow(2, 1023) * 1.999999999999999 // 1.797693134862315e+308
複製代碼