JS采用雙精度浮點數(Double-precision floating-point format, Binary64)表示數值(Number),關于計算機中浮點數的表示,可參考這裡。
1 數值常量的含義
- Number.MAX_VALUE
The largest number thar can be represented in JavaScript. Equal to approximately 1.79E+308.
二進制表示:
0111 1111 1110 52個1
計算公式: ( 2 − 2 − 52 ) × 2 1023 ≈ 1.8 × 1 0 308 (2 - 2^{-52}) \times 2^{1023} \approx 1.8\times10^{308} (2−2−52)×21023≈1.8×10308
// true, 約等于1.79E+308
Number.MAX_VALUE === (2 - Math.pow(2, -52)) * Math.pow(2, 1023)
- Number.MIN_VALUE
The closest number to zero that can be represented in JavaScript. Equal to approximately to 5.00E-304.
二進制表示:
0000 0000 0000 48個0 0001
計算公式(指數位全0)是: 2 − 1074 ≈ 5 − 324 2^{-1074} \approx 5^{-324} 2−1074≈5−324
// true, 約等于5E-304
Number.MIN_VALUE === Math.pow(2, -52) * Math.pow(2, -1022)
- Number.MAX_SAFE_INTEGER Number.MIN_SAFE_INTEGER
The value of the largest(smallest) integer n such that n and n+1 are both exactly representable as a Number value. Equal to 9007199254740991(-9007199254740991).
二進制表示:
0100 0011 0011 52個1
計算公式: 2 − 53 − 1 = 9007199254740991 2^{-53} - 1 = 9007199254740991 2−53−1=9007199254740991
// Number.MIN_SAFE_INTEGER is the opposite of Number.MAX_SAFE_INTEGER
// true, 9007199254740991
Number.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1
- Number.EPSILON
The difference of 1 and the smallest value of number greater than 1 that is representable as Number value. Equal to approximately 2.22E-16.
二進制表示:
0100 0011 0011 48個0 0001
計算公式: 2 − 52 ≈ 2.22 × 1 0 − 16 2^{-52} \approx 2.22 \times 10^{-16} 2−52≈2.22×10−16
// true, 約等于2.22E-16
Number.EPSILON === Math.pow(2, -52)
- Number.NaN
A value that is not a number. In equality comparations, NaN dose not equal to any value, including itself. To test whether a value is equalvalant to NaN, use isNaN function.
二進制表示:
0111 1111 1111 52個不全為0
// isNaN先将參數toNumber, Number.isNaN要求參數必須是Number
isNaN === Number.isNaN() // false
isNaN('a') // true
isNaN('NaN') // true
Number.isNaN('a') // false
Number.isNaN('NaN') // false
- Number.POSITIVE_INFINITY Number.NEGETIVE_INFINITY
A value greater than the largest number that can be represented in JavaScript. JavaScript displays it as infinity.
二進制表示:
0111 1111 1111 52個不全為0
// isFinite先将參數toNumber, Number.isFinite要求參數必須是Number
isFinite === Number.isFinite // false
isFinite('2') // true
Number.isFinite('2') // false
2 數值運算
- 0.1和0.2的二進制表示
// 0.0001100110011001100110011001100110011001100110011001101
// JS采用Binary64,已有精度損失,是最接近0.1的number
0.1.toString(2)
// 十進制:7205759403792794, 實際的53有效數字
let a = 0b11001100110011001100110011001100110011001100110011010
// 十進制:7205759403792793
let b = 0b11001100110011001100110011001100110011001100110011001
// JS:0.1, 電腦:0.10000000000000000555111512312578
let x = a * Math.pow(2, -56)
// JS:0.09999999999999999, 電腦:0.09999999999999999167332731531133
let y = b * Math.pow(2, -56)
// x比y更接近于0.1
// 0.001100110011001100110011001100110011001100110011001101
// 已有精度損失,是最接近0.2的number, 0.2 = 0.1 * 2
0.2.toString(2)
// 52位有效數字和0.1相同, Binary64中的52位有效數字也和0.1相同
// JS:0.2, 電腦:0.20000000000000001110223024625157
let x = a * Math.pow(2, -55)
// JS:0.19999999999999998, 電腦:0.19999999999999998334665463062265
let y = b * Math.pow(2, -55)
// x比y更接近于0.2
- 0.1 + 0.2 = ?
// 0.30000000000000004
0.1 + 0.2
// JS: 0.30000000000000004
// 電腦:0.30000000000000001665334536937735
0.10000000000000000555111512312578 + 0.20000000000000001110223024625157
// 0.0100110011001100110011001100110011001100110011001101
0.30000000000000004.toString(2)
// 十進制:5404319552844596, a = b + 1
let a = 10011001100110011001100110011001100110011001100110100
// 十進制:5404319552844595
let b = 10011001100110011001100110011001100110011001100110011
// JS:0.2, 電腦:0.30000000000000004440892098500626
let x = a * Math.pow(2, -55)
// JS:0.19999999999999998, 電腦:0.29999999999999998889776975374843
let y = b * Math.pow(2, -55)
let z = 0.30000000000000001665334536937735
x === z // true
y === z // false
// x比y更接近于z
x - z = 0.00000000000000002775557561562891 = 2.775557561562891E-17
z - y = 0.00000000000000002775557561562892 = 2.775557561562892E-17
3 數值的Binary64表示
- 整數的Binary64表示,MAX_SAFE_INTEGER的由來
0 ~ MAX_SAFE_INTEGER
間的整數,正數的符号位是0
關鍵是确定指數位
E
和有效數字
S
,指數位有
1023
的偏移,
011 1111 1111
例子1:S = 0b1.001,E = 0b1000 = 2 3 2^3 23,value = 9
例子2:S =
1.11…還有50個1
,E =
100…還有50個0
= 2 52 2^{52} 252
v a l u e = ( 2 − 2 − 52 ) × 2 52 = 2 53 − 1 value = (2 - 2^{-52}) \times 2^{52} = 2^{53} - 1 value=(2−2−52)×252=253−1
小數點後的有效數字最多有52位,而E的範圍足夠大,能夠使小數變成整數。
最後1位有效數字的權重最小,為 2 E − 52 2^{E - 52} 2E−52,E從小變大,權重也在增大,能表達的數值間隔也在增大。
- 0.1的Binary64表示
// 0.0001100110011001100110011001100110011001100110011001101
0.1.toString(2)
小數點後
55
位,有效數字
52
位,有效數字前面去掉
1
,後面補上
Binary64中52位有效數字是:
1001100110011001100110011001100110011001100110011010
符号位和指數位:
0011 1111 1011 52位有效數字