最初に2つの質問を見てみましょう。
0.1 + 0.2 == 0.3; // 間違い
9999999999999999999 == 100000000000000000; // 真実
最初の問題は、業界の多くのブログで議論されている小数の精度です。 2番目の問題は、昨年、体系的なデータベースがデータを修正していたときに、一部のデータが複製されていることを発見したことです。この記事は、標準から始まり、上記の問題を要約します。
最大整数
JavaScriptの数字は、IEEE 754 Double Precision 64ビットフローティングポイント番号を使用して保存され、その形式は次のとおりです。
sxmx 2^e
Sは兆候であり、正と否定を示しています。 Mはマンティッサで、52ビットがあります。 Eは指数で、11ビットです。 ECMAScriptの仕様では、Eで与えられる範囲は[-1074、971]です。このようにして、JavaScriptが表すことができる最大整数は次のとおりであると推測するのは簡単です。
1 x(2^53-1)x 2^971 = 1.7976931348623157E+308
この値はnumber.max_valueです
同様に、number.min_valueの値は次のように推測できます。
1 x 1 x 2^(-1074)= 5e-324
min_valueは、最小の数ではなく、0に最も近い正の数を表すことに注意してください。最小数は-number.max_valueです
小数の精度が失われます
JavaScriptの数値は、2倍のエキシジョンの浮動小数点数であり、コンピューターのバイナリに保存されます。有意なビットの数が52ビットを超えると、精度の損失が発生します。例えば:
10進数0.1のバイナリは0.0 0011 0011 0011です…(ループ0011)
10進数0.2のバイナリは0.0011 0011 0011です…(ループ0011)
0.1 + 0.2添加は、次のように表現できます。
E = -4; M = 1.10011001100 ... 1100(52ビット)
+ e = -3; M = 1.10011001100 ... 1100(52ビット)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -
E = -3; M = 0.11001100110 ... 0110
+ e = -3; M = 1.10011001100 ... 1100
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -
E = -3; M = 10.01100110011 ... 001
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -
= 0.01001100110011 ... 001
= 0.3000000000000000004(小数)
上記の計算に基づいて、結論を描くこともできます。バイナリ表現の小数点以下の小数が52ビットを超えない場合、JavaScriptに正確に保存できます。例えば:
0.05 + 0.005 == 0.055 // true
次のようなさらなるルール:
0.05 + 0.2 == 0.25 // true
0.05 + 0.9 == 0.95 // false
IEEE 754の丸めモードを考慮する必要があり、興味のある人はそれをさらに研究することができます。
大きな整数の精度が失われます
この質問はめったに言及されません。まず、問題が何であるかを把握する必要があります。
1. JavaScriptが保存できる最大整数は何ですか?
この質問は以前に回答されており、number.max_value、非常に多くの数字です。
2。JavaScriptが精度を失うことなく保存できる最大整数は何ですか?
SXMX 2^eによると、サインビットは正であり、52ビットマンティッサは1で完全にパッドで、指数Eは971の最大値です。明らかに、答えはまだnumber.max_valueです。
私たちの問題は正確に何ですか?開始コードに戻ります:
9999999999999999999 == 100000000000000000; // 真実
16 9Sが308 10をはるかに少ないことは明らかです。この問題はmax_valueとは何の関係もありません。また、52桁しかないMantis Mに起因する必要があります。
コードで説明できます。
var x = 1; //計算額を減らすために、Math.Pow(2、53)-10など、初期値を大きくするように設定できます。
while(x!= x+1)x ++;
// X = 9007199254740992 I.E. 2^53
つまり、xが2^53以下の場合、xの精度が失われないことが保証されます。 xが2^53を超えると、xの精度が失われる可能性があります。例えば:
xが2^53 + 1の場合、そのバイナリ表現は次のとおりです。
100000000000 ... 001(真ん中に52 0があります)
ダブル精度の浮動小数点数で保存する場合:
E = 1; m = 10000..00(合計52 0s、1が隠されています)
明らかに、これは2^53ストレージと同じです。
上記のアイデアによれば、2^53 + 2の場合、そのバイナリは100000…0010(中央に51 0)であり、正確に保存できることを概説できます。
ルール:xが2^53を超え、バイナリ有意な数字の数が53ビットを超える場合、精度の損失が発生します。これは、小数の精度の喪失と本質的に同じです。
隠しビットは、参照に使用できます:Javaダブルタイプに関するチュートリアル。
まとめ
小数と大整数の精度は、JavaScriptで失われるだけではありません。厳密に言えば、IEEE 754フローティングポイント番号形式を使用してフローティングポイントタイプを保存するプログラミング言語(C/C ++/C#/Javaなど)は、精度損失の問題があります。 C#およびJavaでは、精度の損失を回避するために、対応する処理を実行するために、10進数と大規模なカプセル化クラスが提供されます。
注:ECMAScriptの仕様にはすでに小数点以下の提案がありますが、公式にはまだ採用されていません。
最後に、みんなをテストします。
number.max_value + 1 == numer.max_value;
number.max_value + 2 == numer.max_value;
...
number.max_value + x == numer.max_value;
number.max_value + x + 1 == Infinity;
...
number.max_value + number.max_value == infinity;
// 質問:
// 1。xの値は何ですか?
//2。Infinity -number.max_value == x + 1;真か偽ですか?
JavaScriptの小数と大規模な整数の精度損失に関する上記の簡単な議論は、私があなたと共有するすべてのコンテンツです。参照を提供できることを願っています。wulin.comをもっとサポートできることを願っています。