Schauen wir uns zuerst zwei Fragen an:
0,1 + 0,2 == 0,3; // FALSCH
9999999999999999999 == 100000000000000000; // WAHR
Das erste Problem ist die Genauigkeit von Dezimalstellen, die in vielen Blogs der Branche diskutiert wurde. Das zweite Problem war, dass im vergangenen Jahr, als eine systematische Datenbank die Daten korrigierte, einige Daten dupliziert wurden. Dieser Artikel beginnt von der Norm und fasst die oben genannten Probleme zusammen.
Maximale Ganzzahl
Die Zahlen in JavaScript werden mit IEEE 754 Double Precision 64-Bit-Schwimmpunktzahlen gespeichert, und ihr Format lautet:
sxmx 2^e
S ist ein Vorzeichenbit, was positiv und negativ anzeigt. M ist die Mantissa mit 52 Bit. E ist der Exponent mit 11 Bit. In der Spezifikation von ECMAScript beträgt der von E angegebene Bereich [-1074, 971]. Auf diese Weise ist es leicht zu schließen, dass die maximale Ganzzahl, die JavaScript darstellen kann, lautet:
1 x (2^53 - 1) x 2^971 = 1,7976931348623157e+308
Dieser Wert ist number.max_value
In ähnlicher Weise kann der Wert der Zahl.min_Value abgeleitet werden als:
1 x 1 x 2^(-1074) = 5E-324
Beachten Sie, dass min_value die positive Zahl darstellt, die 0 am nächsten liegt, nicht die kleinste Zahl. Die kleinste Zahl ist -nummer.max_Value
Die Genauigkeit der Dezimalheit geht verloren
JavaScript-Nummern sind zweifache Gleitkomma-Nummern und werden in Binärdatoren in Computern gespeichert. Wenn die Anzahl der signifikanten Bits 52 Bit überschreitet, wird es Genauigkeitsverlust geben. Zum Beispiel:
Die binäre Binärdatum von 0,1 ist 0,0 0011 0011 0011… (Schleife 0011)
Die Binärdatei von 0,2 ist 0,0011 0011 0011… (Loop 0011)
0,1 + 0,2 Addition kann ausgedrückt werden als:
e = -4; M = 1.10011001100 ... 1100 (52 Bit)
+ e = -3; M = 1.10011001100 ... 1100 (52 Bit)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
e = -3; M = 0,11001100110 ... 0110
+ e = -3; M = 1.10011001100 ... 1100
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
e = -3; M = 10.01100110011 ... 001
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
= 0.01001100110011 ... 001
= 0,30000000000000000004 (Dezimal)
Basierend auf der obigen Berechnung können wir auch eine Schlussfolgerung ziehen: Wenn die endliche Anzahl von Dezimalerdezimalstellen in der binären Darstellung 52 Bit nicht überschreitet, kann sie in JavaScript genau gespeichert werden. Zum Beispiel:
0,05 + 0,005 == 0,055 // True
Weitere Regeln wie:
0,05 + 0,2 == 0,25 // True
0,05 + 0,9 == 0,95 // falsch
Rundungsmodi von IEEE 754 müssen berücksichtigt werden, und diejenigen, die interessiert sind, können es weiter studieren.
Die Genauigkeit der großen Ganzzahlen geht verloren
Diese Frage wird selten erwähnt. Zunächst müssen wir herausfinden, was das Problem ist:
1. Was ist die maximale Ganzzahl, die JavaScript speichern kann?
Diese Frage wurde früher beantwortet und ist number.max_value, eine sehr große Zahl.
2. Was ist die maximale Ganzzahl, die JavaScript speichern kann, ohne Präzision zu verlieren?
Laut Sxmx 2^e ist das Vorzeichenbit positiv, der 52-Bit-Mantissa ist vollständig mit 1 gepolstert und der Exponent E ist der Maximalwert von 971. Offensichtlich ist die Antwort immer noch numme.max_value.
Was genau ist unser Problem? Gehen Sie zurück zum Startcode:
9999999999999999999 == 100000000000000000; // WAHR
Es ist offensichtlich, dass 16 9s weit weniger als 308 10 sind. Dieses Problem hat nichts mit max_value zu tun, und es muss dem Mantis M mit nur 52 Ziffern zugeordnet werden.
Es kann in Code beschrieben werden:
var x = 1; // Um den Berechnungsbetrag zu reduzieren, kann der Anfangswert als größer eingestellt werden, wie z. B. Mathematik (2, 53) - 10
while (x! = x+1) x ++;
// x = 9007199254740992 d. H. 2^53
Das heißt, wenn x kleiner oder gleich 2^53 ist, wird sichergestellt, dass die Genauigkeit von X nicht verloren geht. Wenn x größer als 2^53 ist, kann die Genauigkeit von x verloren gehen. Zum Beispiel:
Wenn x 2^53 + 1 ist, lautet seine binäre Darstellung:
100000000000 ... 001 (es gibt 52 0 in der Mitte)
Beim Speichern mit doppelten Präzisionsschwimmpunktzahlen:
e = 1; M = 10000..00 (insgesamt 52 0s, 1 ist versteckt)
Offensichtlich ist dies das gleiche wie 2^53 Speicher.
Nach der obigen Idee kann beschrieben werden, dass für 2^53 + 2 seine Binärdatei 100000… 0010 (51 0 in der Mitte) beträgt und es auch genau aufbewahrt werden kann.
Regel: Wenn x größer als 2^53 ist und die Anzahl der signifikanten Ziffern von Binärer größer als 53 Bit ist, wird es Genauigkeitsverlust geben. Dies ist im Wesentlichen das gleiche wie der Präzisionsverlust von Dezimalstellen.
Verstecktes Bit kann als Referenz verwendet werden: Ein Tutorial über den Java -Doppel -Typ.
Zusammenfassung
Die Genauigkeit von Dezimalstellen und großen Zahlen geht nicht nur in JavaScript verloren. Streng genommen hat jede Programmiersprache (C/C ++/C#/Java usw.), die das IEEE 754 Floating Point Number -Format zum Speichern von schwimmenden Punkttypen verwendet, Genauigkeitsverlustprobleme. In C# und Java werden Dezimal- und BigDecimal -Einkapselungsklassen bereitgestellt, um eine entsprechende Verarbeitung durchzuführen, um den Genauigkeitsverlust zu vermeiden.
Hinweis: In der ECMascript -Spezifikation gibt es bereits einen Dezimalvorschlag, wurde jedoch noch nicht offiziell angenommen.
Schließlich testen Sie alle:
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;
// Frage:
// 1.. Was ist der Wert von x?
// 2. Infinity - number.max_value == x + 1; Ist wahr oder falsch?
Die obige kurze Diskussion über den Genauigkeitsverlust von Dezimalstellen und DIVE -Ganzzahlen in JavaScript ist der gesamte Inhalt, den ich mit Ihnen teile. Ich hoffe, Sie können Ihnen eine Referenz geben und ich hoffe, Sie können wulin.com mehr unterstützen.