浮點數陷阱 (Floating Point Trap)
大部分語言的數字(像 JavaScript 的 Number 型別)都是採用 IEEE 754 雙精度浮點數 (64-bit double precision floating point) 來表示。
這會帶來一些陷阱:
1. 精度問題
-
有些小數無法被精確表示,例如:
console.log(0.1 + 0.2); // 0.30000000000000004因為二進位制表示時,
0.1和0.2都是無窮小數,只能近似存下來。
2. 大數不精確
-
JavaScript 的
Number安全整數範圍是 -(2^53 - 1) ~ 2^53 - 1。 -
超過這個範圍,整數計算會出錯:
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(9007199254740991 + 1); // 9007199254740992 ✅
console.log(9007199254740991 + 2); // 9007199254740992 ❌
3. 比較陷阱
-
浮點數計算後結果常常不是精確值,導致比較出錯:
console.log(0.1 + 0.2 === 0.3); // false -
一般建議比較時使用「容差」(epsilon):
function isEqual(a, b) {
return Math.abs(a - b) < Number.EPSILON;
}
console.log(isEqual(0.1 + 0.2, 0.3)); // true
BigInt 型別
為了解決 大數精度問題,ES2020 引入了 BigInt 型別。
-
定義
-
在數字後面加
n,或用BigInt()產生:const big1 = 123456789012345678901234567890n;
const big2 = BigInt("9007199254740993");
-
-
範圍
BigInt沒有理論上的最大值或最小值(只受記憶體限制),比Number精確許多。
-
運算
-
可做加減乘除,但 不能直接和 Number 混用:
const a = 10n;
const b = 20n;
console.log(a + b); // 30n
const c = 10;
// console.log(a + c); // ❌ TypeError: Cannot mix BigInt and other types
console.log(a + BigInt(c)); // ✅ 20n
-
-
除法
-
BigInt 除法會直接「取整數」:
console.log(7n / 2n); // 3n (沒有小數部分)
-
-
使用情境
-
金融計算(避免浮點誤差)。
-
密碼學、大數演算法(超過 2^53 的整數)。
-
ID 系統(像資料庫的 long 型別)。
-
總結
-
浮點數陷阱 → 小數計算可能不準,大整數會超出安全範圍。
-
BigInt → 解決大數計算精度問題,但不支援小數。
-
實務做法:
-
金融應用(需要小數點精確) → 用字串處理或
decimal.js等庫。 -
大整數(ID、演算法) → 用
BigInt。 -
一般數值 → 用
Number。
-