Die FallstrickeBei der Berechnung des Rabattpreises eines Produkts auf der Arbeit ergab sich kürzlich immer ein Unterschied von einem Cent im Preis. Geldbezogene Probleme sind heikler. Nach einer Untersuchung stellte sich schließlich heraus, dass es sich um ein Problem mit der nativen toFixed-Methode von JS handelte. Meine Güte, was sind das denn für Regeln? . . (⊙o⊙) FüllmethodeBeeilen Sie sich nicht, das Problem zu untersuchen. Da Sie das Problem gefunden haben, beheben Sie zuerst den Fehler. Wenn die native Methode nicht funktioniert, schreiben Sie einfach selbst eine. Es dauert nur ein paar Minuten, hahaha! /** * Anzahl der Nachkommastellen beibehalten, Nullen automatisch einfügen, aufrunden* @param num: Wert* @param digit: Anzahl der Nachkommastellen* @returns string */ Funktion myFixed(Zahl, Ziffer) { wenn(Objekt.ist(parseFloat(num), NaN)) { return console.log(`Eingehender Wert: ${num} ist keine Zahl`); } Zahl = parseFloat(Zahl); return (Math.round((num + Number.EPSILON) * Math.pow(10, Ziffer)) / Math.pow(10, Ziffer)).toFixed(Ziffer); } Was für eine Grube?OK, da der Fehler nun behoben ist, wollen wir die Geheimnisse von toFixed erkunden. Äh... Zunächst einmal, Em... Lass uns auf Baidu suchen und gezielt nach Baidu-Programmieringenieuren suchen. Tatsächlich gibt es viele Ergebnisse. Es scheint ein klassisches Problem zu sein. Nach einigem Verstehen stellten wir fest, dass die von der Methode toFixed verwendete Rundung nicht die wörtliche Rundung ist, die wir verstehen. Die toFixed-Methode verwendet eine seltsame Methode namens „Runden auf gerade Zahlen“, auch bekannt als Banker-Algorithmus. Was bedeutet das? Vollständige Aussage: „Runde auf die nächste Fünf auf. Wenn die Zahl nach Fünf nicht Null ist, addiere eins. Wenn die Zahl nach Fünf Null ist, überlege, ob sie gerade oder ungerade ist. Wenn die Zahl vor Fünf gerade ist, verwerfe sie. Wenn die Zahl vor Fünf ungerade ist, addiere eins.“ Die allgemeine Bedeutung lautet: Wenn der Wert der verworfenen Ziffer ≤ 4 ist, verwerfen Sie sie; wenn er ≥ 6 ist, addieren Sie sie; wenn er = 5 ist, wird er anhand der Zahl nach 5 bestimmt; wenn nach 5 eine Zahl ungleich Null kommt, runden Sie 5 auf 1; wenn nach 5 keine gültige Zahl kommt, wird dies in zwei Fälle unterteilt: Wenn die Zahl vor 5 eine gerade Zahl ist, runden Sie 5 und addieren Sie sie nicht; wenn die Zahl vor 5 eine ungerade Zahl ist, runden Sie 5 auf 1. Dieser Regel folgend führte ich noch einige Tests mit dem Browser durch, aber es fühlte sich immer noch nicht richtig an. // Die Zahl vor fünf ist eine gerade Zahl, wird sie also nicht verworfen? console.log(1.00000065.toFixed(7)); // 1.0000007 Fehler console.log(1.000000065.toFixed(8)); // 1.00000007 Fehler // Die Zahl vor fünf ist eine ungerade Zahl, es gibt also keine Erhöhung um eins? console.log(1.00000015.toFixed(7)); // 1.0000001 Fehler console.log(1.000000015.toFixed(8)); // 1.00000001 Fehler Warum ist das so? Es ist wirklich verwirrend. . . (︶︿︶) Nach einigen weiteren Untersuchungen habe ich endlich einige Ergebnisse erhalten. Sehen wir uns nun die Definition dieser Methode in der ECMAScript-Spezifikation an. Manchmal ist die Rückkehr zur Spezifikation der zuverlässigste Weg. Das obige Bild ist die Definition der gesamten toFixed-Methode, aber es ist eine übersetzte Version. Es wird einige Unterschiede geben, aber der Unterschied ist nicht groß. Sie können auch auf den obigen Link klicken, um den Originaltext anzuzeigen. Wir konzentrieren uns hauptsächlich auf den roten Kastenteil in der Abbildung und verwenden die Formel, um den verworfenen Wert zu berechnen. Nehmen wir die folgenden beiden Beispiele und testen sie. console.log(1.0000005.toFixed(6)); // 1.000001 richtig console.log(1.00000005.toFixed(7)); // 1.0000000 falsch Erstens sind gemäß den Bedingungen im roten Feld x<10^21, 1,0000005 und 1,00000005 beide kleiner als 10^21, sodass wir zum Spielen direkt die Formel n / 10^ - x verwenden können. Um die Situation zu sehen, setzen wir zunächst x=1.0000005 in die Formel ein: // Angenommen n1 var n1 = 1000000; var x = 1,0000005; var f = 6; console.log((n1 / Math.pow(10, f) - x)); // -5.00000000069889e-7 // Angenommen n2 var n2 = 1000001; var x = 1,0000005; var f = 6; console.log((n2 / Math.pow(10, f) - x)); // 4,9999999998478444e-7 Aus den Ergebnissen können wir ersehen, dass bei n1=1000001 das Ergebnis der Wert ist, der am nächsten bei 0 liegt, also: console.log(1.0000005.toFixed(6)); // 1.000001 ist richtig Versuchen wir es noch einmal, indem wir x=1.00000005 in die Formel einsetzen: // Angenommen n1 var n1 = 10000000; var x = 1,00000005; var f = 7; console.log((n1 / Math.pow(10,f) - x)); // -4.99999999918171056e-8 // Angenommen n2 var n2 = 10000001; var x = 1,00000005; var f = 7; console.log((n2 / Math.pow(10,f) - x)); // 5.000000014021566e-8 Aus den Ergebnissen können wir ersehen, dass bei n2=10000001 das Ergebnis der Wert ist, der am nächsten bei 0 liegt, also: console.log(1.00000005.toFixed(7)); // 1.0000000 Fehler Oh... ich habe gerade gemerkt, dass ich mir hier ein großes Loch gegraben habe. Warum muss ich so viele Nullen verwenden? Mir wird schwindelig vom Zählen. . . Im Allgemeinen sollen Ihnen die obigen Beispiele nur zeigen, wie Sie die Ergebnisse mit den in den Spezifikationen definierten Formeln berechnen. Wenn Sie die Spezifikationen verstehen, ist es kein Problem, sie direkt einzusetzen. ZusammenfassenDies ist das Ende dieses Artikels über das Rundungspräzisionsproblem der toFixed()-Methode in JS. Weitere Informationen zum Rundungspräzisionsproblem von JS toFixed() finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den verwandten Artikeln weiter unten. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen! Das könnte Sie auch interessieren:
|
<<: Schritte zum Bereitstellen mehrerer Tomcat-Dienste mithilfe von DockerFile im Docker-Container
>>: So entfernen Sie die Trennlinie einer Webseitentabelle
Vorwort Wenn wir in der täglichen Entwicklung MyS...
Einführung in Git Git ist eine Open-Source-Versio...
Der Unterschied zwischen „Ersetzen durch“ und „Ei...
Die Testumgebung dieses Experiments: Windows 10+c...
Zusammenfassung Docker-Compose kann problemlos me...
0x0 Parameterüberprüfung Der Großteil der Paramet...
Inhaltsverzeichnis Vorwort vue.config.js-Konfigur...
1. Finden Sie heraus, ob MySQL zuvor installiert ...
Inhaltsverzeichnis Vorwort 1. Systemdienststeueru...
Was ist ein Port? Bei den Ports, auf die wir uns ...
Ergebnis: Implementierungscode: Muss mit der Swip...
Gespeicherte Datenbankprozeduren DROP-VERFAHREN, ...
Dieser Artikel stellt ein interessantes Pseudoele...
Inhaltsverzeichnis Vorwort 1. Ursache des Problem...
Ohne weitere Umschweife hier ein Demobild. Die im...