JavaScriptのnumber
タイプの容量がオーバーフローしています。詳細については、仕様の§8.5を参照してください。これらのIDは文字列である必要があります。
IEEE-754倍精度浮動小数点(JavaScriptが使用する種類の数値)は、(もちろん)すべての数値を正確に表すことはできません。有名なことに、それ0.1 + 0.2 == 0.3
は誤りです。これは、小数に影響するのと同じように整数に影響を与える可能性があります。9,007,199,254,740,991(Number.MAX_SAFE_INTEGER
)を超えると開始します。
Number.MAX_SAFE_INTEGER + 1
( )を超える9007199254740992
と、IEEE-754浮動小数点形式はすべての連続する整数を表すことができなくなります。9007199254740991 + 1
ですが9007199254740992
、フォーマットで表現できないため9007199254740992 + 1
です。次にできるのはです。その後、することはできませんが、できます。 9007199254740992
9007199254740993
9007199254740994
9007199254740995
9007199254740996
その理由は、ビットが不足しているため、1sビットがなくなったためです。最下位ビットは2の倍数を表すようになりました。最終的に、続行すると、そのビットが失われ、4の倍数でのみ機能します。
値はそのしきい値をはるかに上回っているため、最も近い表現可能な値に丸められます。
ES2020では、BigInt
任意の大きさの整数に使用できますが、JSON表現はありません。文字列とリバイバー関数を使用できます。
const jsonString = '{"id":"714341252076979033","type":"FUZZY"}';
// Note it's a string −−−−^−−−−−−−−−−−−−−−−−−^
const obj = JSON.parse(jsonString, (key, value) => {
if (key === "id" && typeof value === "string" && value.match(/^\d+$/)) {
return BigInt(value);
}
return value;
});
console.log(obj);
(Look in the real console, the snippets console doesn't understand BigInt.)
ビットに興味がある場合は、次のようになります。IEEE-754 2進数の倍精度浮動小数点数には、符号ビット、11ビットの指数(数値の全体的なスケールを2の累乗として定義します)があります。これはバイナリ形式であるため])、および52ビットの仮数(ただし、形式は非常に巧妙であるため、これらの52ビットから53ビットの精度が得られます)。指数の使用方法は複雑ですが(ここで説明)、非常にあいまいな言葉で言えば、指数に1を加算すると、指数は2の累乗で使用されるため、仮数の値は2倍になります(ここでも注意してください)。直接ではなく、そこには賢さがあります)。
9007199254740991
それでは、値(aka、Number.MAX_SAFE_INTEGER
)を見てみましょう。
+ ----------- −−−−−−−−−−−−−−符号ビット
/ + ----------- + ---------------- −−−−−−−−−−−−−−指数
/ / | + ----------- + −仮数
/ / | / |
0 10000110011 1111111111111111111111111111111111111111111111111111
= 9007199254740991(Number.MAX_SAFE_INTEGER)
その指数値は10000110011
、仮数に1を加算するたびに、表される数が1ずつ増えることを意味します(整数1は、はるかに早く小数を表す機能を失いました)。
しかし今、その仮数はいっぱいです。その数を超えるには、指数を増やす必要があります。つまり、仮数に1を加えると、表される数の値は1ではなく2増加します(指数は2に適用されるため、この基数は2になります)。 2進浮動小数点数):
+ ----------- −−−−−−−−−−−−−−符号ビット
/ + ----------- + ---------------- −−−−−−−−−−−−−−指数
/ / | + ----------- + −仮数
/ / | / |
0 10000110100 0000000000000000000000000000000000000000000000000000
= 9007199254740992(Number.MAX_SAFE_INTEGER + 1)
9007199254740991 + 1
まあ、とにかくそうなので、それは大丈夫9007199254740992
です。だが!を表すことはできません9007199254740993
。ビットが不足しています。仮数に1だけを追加すると、値に2が追加されます。
+ ----------- −−−−−−−−−−−−−−符号ビット
/ + ----------- + ---------------- −−−−−−−−−−−−−−指数
/ / | + ----------- + −仮数
/ / | / |
0 10000110100 0000000000000000000000000000000000000000000000000001
= 9007199254740994(Number.MAX_SAFE_INTEGER + 3)
値を大きくすると、フォーマットは奇数を表すことができなくなり、指数が大きすぎます。
最終的に、仮数ビットが再び不足し、指数を増やす必要があるため、4の倍数、次に8の倍数、次に16の倍数しか表現できなくなります。