JavaScriptと9007199254740993

こんばんわ
友達に聞かれて即答できなかったので調べてみました

9007199254740993が1減る?

タイトルの通りですが

// コレをやると
console.log(9007199254740993);

// こうなります
9007199254740992

実際は1減ったとかではなく

これも

for (var i = 9007199254740993; i + 100 > i; i += 1) console.log(i);

全てが 9007199254740992 になります。

理由

ECMAScriptの数値はIEEE 754の倍精度浮動小数点数という仕様になってます
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf

4.3.19
Number value
primitive value corresponding to a double-precision 64-bit binary format IEEE 754 value
NOTE A Number value is a member of the Number type and is a direct representation of a number.
4.3.20
Number type
set of all possible Number values including the special ―Not-a-Number‖ (NaN) values, positive infinity, and 
negative infinity


よって、暗黙bitを含めた53bitの仮数部を超えると精度を保てなくなります

console.log(9007199254740993..toString(2).length);
// => 54

@y_imayaさん
教えて頂きありがとうございました〜


ビット演算の場合

また、ビット演算は内部的に32bit整数に変換する仕様からして

// 1 << 30
Math.pow(2,30)|0;
1073741824

// 1 << 31は、32bitの2の補数表現に
Math.pow(2, 31)|0;
-2147483648

V8の場合31bitまではSmiで表現されるとのことですが、今度もう少し調べてみますー。
併せて知らないと詰まるネタだなぁ思いました


おしまい。

開眼!  JavaScript ―言語仕様から学ぶJavaScriptの本質

開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質