≪ Today I learned. RSS購読
公開日
タグ
JavaScript
著者
ダーシノ(@bc_rikko)

BigIntで発生する誤差と対策

ロシアの裁判所がとんでもない額(200溝ドル = 2*10^34)という賠償請求を命じた。

JavaScriptで安全に扱える数はNumber.MAX_SAFE_INTEGERの値である9007199254740991(2^53-1)までだ。なので、200溝ドルという桁を扱うためにはBigIntを使う必要がある。

BigIntを使うにはBigIntコンストラクタを使うか、数値リテラルの末尾にnをつけて表現する。

BigIntの表現

> 20000000000000000000000000000000000
2e+34

> BigInt(20000000000000000000000000000000000)
19999999999999998911504619740856320n

> 20000000000000000000000000000000000n
20000000000000000000000000000000000n

?!?!

BigInt(Number)で変換すると誤差が生じる。

BigIntコンストラクタで生じる誤差

BigInt(20000000000000000000000000000000000)のようにすると、コンストラクタにわたる前に数値が丸められてしまう。そのため、BigIntはすでにNumber型として丸められた19999999999999998911504619740856320を受け取るので結果に誤差が生じる。

// 1. BigIntコンストラクタを使う
BigInt(20000000000000000000000000000000000)

// 2. 数値リテラルの部分が丸められてからBigIntに変換される
BigInt(19999999999999998911504619740856320)

// 3. 丸められた数値をBigIntが返ってくる
19999999999999998911504619740856320n

BigIntコンストラクタで誤差を避ける方法

BigInt('20000000000000000000000000000000000')のように文字列リテラルでコンストラクタにわたすことで、数値が丸められることなくBigIntに変換される。

> BigInt('20000000000000000000000000000000000')
20000000000000000000000000000000000n