1、Number.isInteger()
方法用來判斷給定的參數是否爲整數。
由於 JavaScript 採用 IEEE 754 標準,數值存儲爲64位雙精度格式,數值精度最多可以達到 53 個二進制位(1 個隱藏位與 52 個有效位)。如果數值的精度超過這個限度,第54位及後面的位就會被丟棄,這種情況下,Number.isInteger
可能會誤判。
Number.isInteger(3.0000000000000002) // true
上面代碼中,Number.isInteger
的參數明明不是整數,但是會返回true
。原因就是這個小數的精度達到了小數點後16個十進制位,轉成二進制位超過了53個二進制位,導致最後的那個2
被丟棄了。
類似的情況還有,如果一個數值的絕對值小於Number.MIN_VALUE
(5E-324),即小於 JavaScript 能夠分辨的最小值,會被自動轉爲 0。這時,Number.isInteger
也會誤判。
Number.isInteger(5E-324) // false
Number.isInteger(5E-325) // true
上面代碼中,5E-325
由於值太小,會被自動轉爲0,因此返回true
。
總之,如果對數據精度的要求較高,不建議使用Number.isInteger()
判斷一個數值是否爲整數。
2、小數點後16位精度計算錯誤問題
ES6 在Number
對象上面,新增一個極小的常量Number.EPSILON
。根據規格,它表示 1 與大於 1 的最小浮點數之間的差。
對於 64 位浮點數來說,大於 1 的最小浮點數相當於二進制的1.00..001
,小數點後面有連續 51 個零。這個值減去 1 之後,就等於 2 的 -52 次方。
Number.EPSILON === Math.pow(2, -52)
// true
Number.EPSILON
// 2.220446049250313e-16
Number.EPSILON.toFixed(20)
// "0.00000000000000022204"
Number.EPSILON
實際上是 JavaScript 能夠表示的最小精度。誤差如果小於這個值,就可以認爲已經沒有意義了,即不存在誤差了。
引入一個這麼小的量的目的,在於爲浮點數計算,設置一個誤差範圍。我們知道浮點數計算是不精確的。
0.1 + 0.2
// 0.30000000000000004
0.1 + 0.2 - 0.3
// 5.551115123125783e-17
5.551115123125783e-17.toFixed(20)
// '0.00000000000000005551'
上面代碼解釋了,爲什麼比較0.1 + 0.2
與0.3
得到的結果是false
。
0.1 + 0.2 === 0.3 // false
Number.EPSILON
可以用來設置“能夠接受的誤差範圍”。比如,誤差範圍設爲 2 的-50 次方(即Number.EPSILON * Math.pow(2, 2)
),即如果兩個浮點數的差小於這個值,我們就認爲這兩個浮點數相等。
5.551115123125783e-17 < Number.EPSILON * Math.pow(2, 2)
// true
因此,Number.EPSILON
的實質是一個可以接受的最小誤差範圍。
function withinErrorMargin (left, right) {
return Math.abs(left - right) < Number.EPSILON * Math.pow(2, 2);
}
0.1 + 0.2 === 0.3 // false
withinErrorMargin(0.1 + 0.2, 0.3) // true
1.1 + 1.3 === 2.4 // false
withinErrorMargin(1.1 + 1.3, 2.4) // true
上面的代碼爲浮點數運算,部署了一個誤差檢查函數。