Grund: JS verarbeitet die Hinzufügung, Subtraktion, Multiplikation und Aufteilung von Dezimalstellen gemäß 2. Auf der Grundlage von Arg1 wird die Genauigkeit von Arg2 erweitert oder umgekehrt erweitert, sodass die folgende Situation auftritt.
Das Problem des Hinzufügens, Subtrahierens, Multiplikation und Aufteilung von Dezimalpunkten in JavaScript (JS) ist ein Fehler in JS wie 0,3*1 = 0,299999999999 usw. Die folgenden Listen sind vier JS -Algorithmen, die die entsprechende Genauigkeit perfekt berechnen können.
Funktion ACCDIV (arg1, arg2) {var t1 = 0, t2 = 0, r1, r2; try {t1 = arg1.toString (). split (".") [1] .Length} catch (e) {} try {t2 = arg2.toString (). Split (") [1] .Length} catch (e) {} mit (math) {r1 = nummer (arg1.tostring (). r2 = nummer (arg2.tostring (). ersetzen (".", ") return accmul ((r1/r2), pow (10, t2-t1)); }} // Multiple Funktion accmul (arg1, arg2) {var m = 0, s1 = arg1.toString (), s2 = arg2.toString (); Versuchen Sie {m+= s1.split (".") [1] .Length} catch (e) {} try {m+= s2split (".") [1] .Length} catch (e) {} Return -Nummer (S1.Replace (". Accadd (arg1, arg2) {var r1, r2, m; try {r1 = arg1.toString (). split (".") [1] .Length} catch (e) {r1 = 0} try {r2 = arg2.toString (). Split (") [1] .Length} catch (e) {r2 = 0} mmm = math. } // Subtraktionsfunktion subtr (arg1, arg2) {var r1, r2, m, n; try {r1 = arg1.toString (). split (".") [1] .Length} catch (e) {r1 = 0} try {r2 = arg2.toString (). Split (") [1] .Length} catch (e) {r2 = 0} mmatmmath.pow (10, math.max (10, math.max (10, math.max n = (r1> = r2)? R1: R2; return ((arg1*m-arg2*m)/m) .Tofixed (n); }Lassen Sie uns den Verlust der digitalen Präzision in JavaScript analysieren.
1. Einige typische Probleme des digitalen Präzisionsverlusts von JS
1. Fügen Sie zwei einfache schwimmende Punktzahlen hinzu
0,1 + 0,2! = 0,3 // True
Firebug
Dies ist wirklich kein Firebug -Problem, Sie können es mit Alarm (haha, scherzhaft) versuchen.
Schauen Sie sich die Berechnungsergebnisse von Java an
Schauen Sie sich Python an
2. Operation der großen Ganzzahl
999999999999999999 == 10000000000000000001 //?
Firebug
Die 16-stelligen und 17-stelligen Zahlen sind tatsächlich gleich, es ist unangemessen.
Auch wie
var x = 9007199254740992x + 1 == x //?
Siehe die Ergebnisse
Die drei Ansichten wurden erneut untergraben.
3.. Tofixed wird nicht rund (Chrom)
1.335.Tofixed (2) // 1.33
Firebug
Es gab Fälle von inkonsistenten Preisen in Chrome und anderen Browsern online, und genau auf das Problem der mit dem tozifizierten Kompatibilität zurückzuführen.
2. Gründe für JS -Zahlenverlustgenauigkeit
Einige Zahlen können nicht durch Computer -binäre Implementierungen und Bit -Grenzen endlich ausgedrückt werden. Genauso wie einige irrationale Zahlen können nicht endgültig dargestellt werden, wie z. Wie gezeigt
Bedeutung
Schwimmende Punktzahlen, z.
0,1 >> 0,0001 1001 1001 1001… (1001 Infinite Loop) 0,2 >> 0,0011 0011 0011 0011… (0011 Infinite Loop)
Zu diesem Zeitpunkt können Sie es nur umrunden, indem Sie das Dezimalsystem imitieren, aber es gibt nur zwei binäre Systeme: 0 und 1, also wird es 0 und rundet es um 1. aus. Dies ist der grundlegende Grund, warum einige schwimmende Punktzahlen in Computern Fehler und verlorene Genauigkeit sind.
Der Genauigkeitsverlust von großen ganzen Zahlen entspricht im Wesentlichen mit schwimmenden Punktzahlen. Das maximale Mantissa -Bit beträgt 52 Bits, daher ist die maximale Ganzzahl, die in JS genau dargestellt werden kann.
Mehr als 9007199254740992 kann die Genauigkeit verlieren
9007199254740992 >> 1000000000000000...000 // Total 53 09007199254740992 + 1 >> 10000000000000000...001 // In the middle 52 09007199254740992 + 2 >> 10000000000000000...010 // In the middle 51 0
Tatsächlich
9007199254740992 + 1 // verloren 9007199254740992 + 2 // nicht verloren 9007199254740992 + 3 // verloren 9007199254740992 + 4 // nicht verloren
Die Ergebnisse sind in der Abbildung dargestellt
Wie oben erwähnt, können wir wissen, dass die scheinbar endlichen Zahlen in der binären Darstellung des Computers unendlich sind. Aufgrund der Speicherbitgrenze gibt es "Get -Away" und der Genauigkeitsverlust tritt auf.
Für eine eingehende Analyse können Sie dieses Papier lesen (lang und stinkend): Was jeder Informatiker über die Gleitkomma-Arithmetik wissen sollte
3. Lösung
Für Ganzzahlen kann die Wahrscheinlichkeit von Problemen im Front-End relativ niedrig sein. Immerhin müssen nur wenige Unternehmen super große Ganzzahlen verwenden. Solange das Berechnungsergebnis die Mathematik nicht überschreitet, wird die Genauigkeit nicht verloren.
Für Dezimalstellen besteht immer noch viele Probleme mit dem Front-End, insbesondere auf einigen E-Commerce-Websites, die Daten wie Mengen umfassen. Lösung: Geben Sie die Dezimalzahl in die Ganzzahl (mehrfach mehrfach) und schrumpfen Sie dann auf das ursprüngliche Multiple (Teilen Sie mehrere) zurück)
// 0,1 + 0,2 (0,1*10 + 0,2*10) / 10 == 0,3 // True
Das Folgende ist ein Objekt, das ich geschrieben habe, um den Verlust der Genauigkeit von Addition, Subtraktion, Multiplikation und Aufteilung der Dezimalstellen zu blockieren. Natürlich darf die konvertierte Ganzzahl 9007199254740992 überschreiten.
/*** FloatObj enthält vier Methoden: Addition, Subtraktion, Multiplikation und Teilung, die sicherstellen können, dass die Berechnung der Gleitpunktzahl nicht die Genauigkeit verliert. Die Ursache ist, dass einige Zahlen nicht in binärer und implementierter Bitgrenzen ausgedrückt werden können. Beispielsweise verwendet JavaScript numerische Typen mit 64-Bit-Speicher, sodass diejenigen, die sie überschreiten, verworfen werden. Der Teil, der verloren ist, ist der Teil, der in Genauigkeit verloren geht. ** ** method *** add / subtract / multiply /divide** ** explanation *** 0.1 + 0.2 == 0.300000000000000004 (0.0000000000000004 more) * 0.2 + 0.4 == 0.60000000000000000001 (0.00000000000000001) * 19.9 * 100 == 1989.9999999999999998 . eine ganze Zahl und gibt eine Ganzzahl und Mehrfach zurück. For example, 3.14 >> 314, the multiple is 100* @param floatNum {number} decimal* @return {object}* {times:100, num: 314}*/function toInteger(floatNum) {var ret = {times: 1, num: 0}if (isInteger(floatNum)) {ret.num = floatNumreturn ret}var strfi = floatNum + '' var dotpos = strfi.indexof ('.') var len = strfi.substr (dotpos + 1) .LengthVar Times = Math.Pow (10, len) var intnum = parseInt (floatnum* mal + 0,5, 10) ret.times = Timesret = Multiplikation, Multiplaction, Division und Divisions -Operations -Divisions -Abteilung. Genauigkeit ist nicht verloren* Idee: Vergrößern Sie die Dezimalzahl in eine Ganzzahl (Multiplikator), führen Sie arithmetische Operationen aus und schrumpfen dann zu einer Dezimalzahl (geteilt) ** @param a {number} Betriebsnummer 1* @param b {number} Betriebsnummer 2* @Param -Number {Number} -Anparam. op {string} Operation type, with addition, subtraction, multiplication and division (add/subtract/multiply/divide)**/function operation(a, b, digits, op) {var o1 = toInteger(a)var o2 = toInteger(b)var n1 = o1.numvar n2 = o2.numvar t1 = o1.timesvar t2 = o2.timesvar max = t1 > T2? t1 : t2var result = nullswitch (op) {case 'add':if (t1 === t2) { // Two decimal places are the same result = n1 + n2} else if (t1 > t2) { // o1 decimal places greater than o2result = n1 + n2 * (t1 / t2)} else { // o1 decimal places less than o2result = n1 * (t2 / t1) + n2}return result / maxcase 'subtract':if (t1 === t2) {result = n1 - n2} else if (t1 > t2) {result = n1 - n2 * (t1 / t2)} else {result = n1 * (t2 / t1) - n2}return result / maxcase 'multiply':result = (n1 * n2) / (t1 * t2) return resultcase 'divide':result = (n1 / n2) * (t2 / t1)return result}}// Four interfaces of addition, subtraction, multiplication and division function add(a, b, digits) {return operation(a, b, digits, 'add')}function subtract(a, b, digits) {return operation(a, b, digits, 'subtract')}function multiply(a, B, Digits) {Rückgabeoperation (a, b, Ziffern, 'multiplizieren')} Funktion Divide (A, B, Digits) {Return Operation (A, B, Digits, 'Divide')} // exportsreturn {add: add: subtract: subtract, multiply, multiply, division: divise}}} ();Tofixeds Fix ist wie folgt
// Tofixed Fix Function Tofixed (num, s) {var Times = math.pow (10, s) var des = num * mal + 0,5des = parseInt (Des, 10) / TimesReturn Des + ''}