JavaScript BigInt:優雅解決大數字精度問題


Posted by Andy Tsai on 2025-07-29

在 JavaScript 開發中,處理大數字時你可能會遇到一個隱藏陷阱:精度丟失。今天我們來聊聊這個問題,以及 BigInt 如何優雅地解決它。

問題背景:Number 的精度限制

為什麼會有精度問題?

JavaScript 的 Number 型別基於 IEEE 754 雙精度浮點數標準,其能夠精確表示的整數範圍有限:

// 安全整數範圍
console.log(Number.MAX_SAFE_INTEGER); // 9,007,199,254,740,991 (2^53 - 1)
console.log(Number.MIN_SAFE_INTEGER); // -9,007,199,254,740,991 (-(2^53 - 1))

精度丟失的實際案例

超過安全範圍的數字運算會出現精度丟失:

// 精度丟失範例
console.log(9007199254740993);     // 預期:9007199254740993
                                   // 實際:9007199254740992 ❌ 精度丟失

console.log(150121231230120301);   // 預期:150121231230120301
                                   // 實際:150121231230120300 ❌ 精度丟失

BigInt

什麼是 BigInt?

BigInt 是 ES2020 (ES11) 引入的新原始型別,專門用於處理任意精度的整數,完全不受 Number.MAX_SAFE_INTEGER 限制。

建立 BigInt

// 方法一:字面值語法(推薦)
const bigInt1 = 123n;

// 方法二:BigInt 建構函數
const bigInt2 = BigInt("123456789012345678901234567890");
const bigInt3 = BigInt(123);

基本運算

const a = 123n;
const b = 456n;

console.log(a + b);    // 579n
console.log(a * b);    // 56088n
console.log(a - b);    // -333n
console.log(b / a);    // 3n(整數除法)

重要限制

⚠️ BigInt 無法與 Number 直接混用

// ❌ 錯誤用法
1n + 1;        // TypeError: Cannot mix BigInt and other types

// ✅ 正確用法
1n + 1n;       // 2n
Number(1n) + 1; // 2

實戰應用:LeetCode Plus One

題目描述

給定一個由數字組成的陣列 digits,代表一個大整數。將此整數加 1 後,回傳結果陣列。

範例:

// 範例 1
輸入: [1,2,3]
輸出: [1,2,4]
解釋: 123 + 1 = 124

// 範例 2  
輸入: [9]
輸出: [1,0]
解釋: 9 + 1 = 10

傳統解法的問題

最直覺的想法可能是這樣寫:

function plusOne(digits) {
    let number = Number(digits.join("")) + 1; 
    return number.toString().split("").map(v => Number(v));
}

看起來沒什麼問題,不過就是將陣列轉成數字加 1,然後再轉回去。

但送出後就會發現,咦!竟然失敗了:

plusOne([6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,5,4,3]);
// 預期: [6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,5,4,4]
// 實際: [6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,0,0,0] 💥

debug 後就會發現 6145390195186705543 + 1 會變成 6145390195186705000
這,就是精度問題在作怪!

BigInt 解法

使用 BigInt 可以優雅解決這個問題:

function plusOne(digits) {
    const number = BigInt(digits.join("")) + 1n;
    return number.toString().split("").map(v => Number(v));
}

// 測試結果
console.log(plusOne([6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,5,4,3]));
// 輸出: [6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,5,4,4] ✅

解法步驟:

  1. digits.join("") 將陣列轉為字串
  2. BigInt() 轉換為大整數
  3. 加上 1n(BigInt 型別的 1)
  4. 轉回字串再拆分成數字陣列

總結

BigInt 為 JavaScript 帶來了處理大整數的能力,解決了 Number 型別的精度限制。
另外,雖然我們用 BigInt 優雅解決了 LeetCode 這題,但這題的本質是想考進位處理演算法。
所以,如果你是為了練演算法,不妨再動手實作一次進位邏輯。

參考資料


#javascript #bigint







Related Posts

漫談傳輸介面-PCIe

漫談傳輸介面-PCIe

程式基礎 —— Javascript 動手做 Part2

程式基礎 —— Javascript 動手做 Part2

【單元測試的藝術】Chap 10: 遺留程式碼

【單元測試的藝術】Chap 10: 遺留程式碼


Comments