BigIntと精度の話|なぜ巨大な数の進数変換が正確にできるのか
なぜ「精度」が問題になるか
進数変換ツール は内部でBigIntを使っています。普通の Number ではなくBigIntを選んだ理由は、JavaScriptの数値型の制限を回避するためです。
JavaScriptの Number は53bit整数まで
Number はIEEE 754倍精度浮動小数点(double)で、整数として正確に扱えるのは 2^53 - 1 = 9007199254740991 まで。これを Number.MAX_SAFE_INTEGER と呼びます。
9007199254740991 + 1 === 9007199254740991 + 2 // true(同じ値として扱われる)
53bitを超えると桁が飛ぶようになり、加算が機能しなくなります。
16進で言うと
2^53 - 1 = 0x1FFFFFFFFFFFFF
つまり16進13桁あたりで桁あふれ。メモリアドレス(64bit)、SHA-256(256bit)、IPv6(128bit)はすべて Number では扱えません。
BigIntとは
ES2020で追加された任意精度整数型。リテラルは末尾 n を付けます:
const a = 9007199254740993n;
const b = a + 1n; // 9007199254740994n(正確)
- 任意桁数の整数を扱える
- 演算は通常の
+,-,*,/,%が使える - ただし
Numberと直接は混在できない(型変換が必要) - 浮動小数点はサポートしない(整数専用)
本ツールの内部実装
進数変換ツール の変換ロジックは大まかに:
// 文字列 → BigInt
function parseFromBase(input, base) {
let value = 0n;
for (const c of input) {
const digit = digitOf(c);
value = value * BigInt(base) + BigInt(digit);
}
return value;
}
// BigInt → 文字列
function toBase(value, base) {
const digits = [];
while (value > 0n) {
digits.unshift(charAt(value % BigInt(base)));
value = value / BigInt(base);
}
return digits.join("");
}
全段階でBigIntを使うため、入力がどれだけ大きくても精度を失いません。
実際の動作確認
Number で動かない例
parseInt("1234567890123456789", 10)
// → 1234567890123456800(末尾が変わる!)
parseInt は内部で Number を使うため、19桁になると下位の桁が失われます。
BigInt なら正確
BigInt("1234567890123456789")
// → 1234567890123456789n(正確)
進数変換ツール も parseInt ではなく BigInt 経路で処理しているため、19桁、30桁、100桁の数値も正確に変換できます。
どんな場面で巨大な整数が必要か
暗号鍵・トークン
RSA秘密鍵: 2048bit〜4096bit、楕円曲線: 256bit〜512bit。これらは10進で何百桁にもなります。
IPv6アドレス
128bit。
2001:0db8:85a3:0000:0000:8a2e:0370:7334
↓ 16進連結
20010db885a3000000008a2e03707334
↓ 10進
42540766452641154071740215577757643572
37桁ありますが、進数変換ツールでBigInt経由なら正確に変換できます。
ハッシュ値
SHA-256: 256bit = 16進64桁。生のハッシュバイトを整数として扱いたい場合。
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
これを10進に変換できます(あまりやらない用途ですが)。
暗号通貨のweiやsatoshi
イーサリアムの最小単位 wei は1 ETH = 10^18 wei。18桁の整数が常に出てきます。
BigIntの制限
浮動小数点はできない
1n / 3n // 0n(整数除算、小数点以下は切り捨て)
「123.456 を10進から16進」のような小数を含む変換は本ツール非対応です。整数のみ。
Numberとの直接混在不可
1n + 1 // TypeError
1n + 1n // 2n(OK)
Number(1n) + 1 // 2(型変換すればOK)
進数変換以外でBigIntが効く場面
| 用途 | 例 |
|---|---|
| 大きなIDの生成 | Snowflake ID(64bit) |
| タイムスタンプの高精度演算 | BigInt(Date.now()) * 1000000n + nanoseconds |
| 金額計算(最小単位を整数化) | wei、satoshi、銭 |
| ファイルサイズ集計 | TB級ファイルの総和 |
関連記事
「Number で扱えない大きさの整数を、進数変換できる」というのが、本ツールがBigIntを採用する理由です。