JavaScriptで整数をインクリメントしていくと、あるところでそれ以上大きくならなくなる。
9007199254740992をインクリメントしても9007199254740992になってしまう。
JavaScriptのNumber型は64bitの倍精度浮動小数点型で表現されるので、整数を正確に表せるのは仮数部の53bit分ということになる。
16進数で書くとこんな。
0x1FFFFFFFFFFFFF
9007199254740991(10進)
だから、9007199254740991を超えると整数の値が不正確なものになってしまう。
試しに以下を実行して、10進表現と2進表現を表示すると
9007199254740992が2回現れたり、9007199254740996が3回現れたりするけど、9007199254740993や9007199254740995というのは現れない。
これは仮数部の端数処理が2進数の再近接偶数丸めで行われているからだ。端数は最も近い表現可能な数に丸められるけど、上下の表現可能な数から等距離の場合、丸め後の値が偶数になるように丸められる。
その結果、以下の矢印の方向にまるめられ、9007199254740992が2回出現し、9007199254740996が3回出現することになる。
9007199254740992: 10000000000000000000000000000000000000000000000000000 0
9007199254740993: 10000000000000000000000000000000000000000000000000000 1↓
9007199254740994: 10000000000000000000000000000000000000000000000000001 0
9007199254740995: 10000000000000000000000000000000000000000000000000001 1↑
9007199254740996: 10000000000000000000000000000000000000000000000000010 0
9007199254740997: 10000000000000000000000000000000000000000000000000010 1↓
9007199254740998: 10000000000000000000000000000000000000000000000000011 0
for (let i = 0; i < veryLargeNumber; i++) { ... }
... 9007199254740989 9007199254740990 9007199254740991 9007199254740992 9007199254740992 9007199254740992 9007199254740992 ...
9007199254740992をインクリメントしても9007199254740992になってしまう。
JavaScriptのNumber型は64bitの倍精度浮動小数点型で表現されるので、整数を正確に表せるのは仮数部の53bit分ということになる。
16進数で書くとこんな。
0x1FFFFFFFFFFFFF
9007199254740991(10進)
だから、9007199254740991を超えると整数の値が不正確なものになってしまう。
試しに以下を実行して、10進表現と2進表現を表示すると
for (let i = 0; i < 10; i++) { print(0x1FFFFFFFFFFFFF + i + ': ' + (0x1FFFFFFFFFFFFF + i).toString(2)); }
9007199254740991: 11111111111111111111111111111111111111111111111111111 9007199254740992: 100000000000000000000000000000000000000000000000000000 9007199254740992: 100000000000000000000000000000000000000000000000000000 9007199254740994: 100000000000000000000000000000000000000000000000000010 9007199254740996: 100000000000000000000000000000000000000000000000000100 9007199254740996: 100000000000000000000000000000000000000000000000000100 9007199254740996: 100000000000000000000000000000000000000000000000000100 9007199254740998: 100000000000000000000000000000000000000000000000000110 9007199254741000: 100000000000000000000000000000000000000000000000001000 9007199254741000: 100000000000000000000000000000000000000000000000001000
9007199254740992が2回現れたり、9007199254740996が3回現れたりするけど、9007199254740993や9007199254740995というのは現れない。
これは仮数部の端数処理が2進数の再近接偶数丸めで行われているからだ。端数は最も近い表現可能な数に丸められるけど、上下の表現可能な数から等距離の場合、丸め後の値が偶数になるように丸められる。
その結果、以下の矢印の方向にまるめられ、9007199254740992が2回出現し、9007199254740996が3回出現することになる。
9007199254740992: 10000000000000000000000000000000000000000000000000000 0
9007199254740993: 10000000000000000000000000000000000000000000000000000 1↓
9007199254740994: 10000000000000000000000000000000000000000000000000001 0
9007199254740995: 10000000000000000000000000000000000000000000000000001 1↑
9007199254740996: 10000000000000000000000000000000000000000000000000010 0
9007199254740997: 10000000000000000000000000000000000000000000000000010 1↓
9007199254740998: 10000000000000000000000000000000000000000000000000011 0
0 件のコメント:
コメントを投稿