832 Stimmen

Wie geht man mit der Genauigkeit von Fließkommazahlen in JavaScript um?

Ich habe das folgende Dummy-Testskript:

function test() {
  var x = 0.1 * 0.2;
  document.write(x);
}
test();

So wird das Ergebnis gedruckt 0.020000000000000004 während es einfach drucken sollte 0.02 (wenn Sie Ihren Taschenrechner benutzen). Soweit ich verstanden habe, ist dies auf Fehler in der Genauigkeit der Fließkommamultiplikation zurückzuführen.

Hat jemand eine gute Lösung, damit ich in einem solchen Fall das richtige Ergebnis erhalte? 0.02 ? Ich weiß, es gibt Funktionen wie toFixed oder Rundung wäre eine weitere Möglichkeit, aber ich möchte wirklich die ganze Zahl ohne Kürzung und Rundung gedruckt haben. Ich wollte nur wissen, ob jemand von Ihnen eine schöne, elegante Lösung hat.

Natürlich werde ich sonst auf 10 Stellen oder so aufrunden.

157 Stimmen

Eigentlich liegt der Fehler daran, dass es keine Möglichkeit gibt, die 0.1 in eine endliche binäre Gleitkommazahl.

19 Stimmen

Die meisten Brüche lassen sich nicht mit exakter Genauigkeit in eine Dezimalzahl umwandeln. Eine gute Erklärung finden Sie hier: docs.python.org/release/2.5.1/tut/node16.html

8 Stimmen

12voto

user10089632 Punkte 4722

Beachten Sie, dass dieses Verhalten für den allgemeinen Gebrauch wahrscheinlich akzeptabel ist.
Das Problem entsteht, wenn man diese Fließkommawerte vergleicht, um eine geeignete Aktion zu bestimmen.
Mit der Einführung von ES6 wird eine neue Konstante Number.EPSILON wird definiert, um die akzeptable Fehlerspanne zu bestimmen:
Anstatt also den Vergleich wie folgt durchzuführen

0.1 + 0.2 === 0.3 // which returns false

können Sie eine benutzerdefinierte Vergleichsfunktion definieren, etwa so:

function epsEqu(x, y) {
    return Math.abs(x - y) < Number.EPSILON;
}
console.log(epsEqu(0.1+0.2, 0.3)); // true

Quelle: http://2ality.com/2015/04/numbers-math-es6.html#numberepsilon

12voto

Erikas Pliauksta Punkte 1312

dezimal.js , big.js o bignumber.js kann verwendet werden, um Probleme bei der Gleitkommamanipulation in Javascript zu vermeiden:

0.1 * 0.2                                // 0.020000000000000004
x = new Decimal(0.1)
y = x.times(0.2)                          // '0.2'
x.times(0.2).equals(0.2)                  // true

big.js: minimalistisch; benutzerfreundlich; Genauigkeit wird in Dezimalstellen angegeben; Genauigkeit wird nur auf die Division angewendet.

bignumber.js: Basen 2-64; Konfigurationsoptionen; NaN; Unendlich; Genauigkeit in Dezimalstellen; Genauigkeit nur bei Division; Basispräfixe.

decimal.js: Basen 2-64; Konfigurationsoptionen; NaN; Unendlich; nicht-ganzzahlige Potenzen, exp, ln, log; Genauigkeit in signifikanten Ziffern angegeben; Genauigkeit immer angewendet; Zufallszahlen.

Link zu detaillierten Vergleichen

11voto

Tom Punkte 127

Die Funktion round() auf phpjs.org funktioniert gut: http://phpjs.org/functions/round

num = .01 + .06;  // yields 0.0699999999999
rnum = round(num,12); // yields 0.07

11voto

Keith Punkte 141163

Das Ergebnis, das Sie erhalten haben, ist korrekt und ziemlich einheitlich für Fließkomma-Implementierungen in verschiedenen Sprachen, Prozessoren und Betriebssystemen - das Einzige, was sich ändert, ist der Grad der Ungenauigkeit, wenn die Fließkommazahl tatsächlich ein Double (oder höher) ist.

0,1 in binären Fließkommazahlen ist wie 1/3 in Dezimalzahlen (d.h. 0,333333333333333... für immer), es gibt einfach keinen genauen Weg, damit umzugehen.

Wenn Sie es mit Schwimmern zu tun haben immer rechnen Sie mit kleinen Rundungsfehlern, so dass Sie auch das angezeigte Ergebnis immer auf eine sinnvolle Größe runden müssen. Im Gegenzug erhalten Sie eine sehr schnelle und leistungsstarke Arithmetik, da alle Berechnungen im nativen Binärformat des Prozessors durchgeführt werden.

In den meisten Fällen besteht die Lösung nicht darin, zur Festkommaarithmetik zu wechseln, vor allem, weil sie viel langsamer ist und man in 99 % der Fälle die Genauigkeit nicht braucht. Wenn Sie mit Sachen zu tun haben, die dieses Maß an Genauigkeit benötigen (z. B. Finanztransaktionen), ist Javascript wahrscheinlich sowieso nicht das beste Werkzeug (da Sie die Festkommatypen durchsetzen wollen, ist eine statische Sprache wahrscheinlich besser).

Wenn Sie nach einer eleganten Lösung suchen, dann fürchte ich, dass es das ist: Fließkommazahlen sind schnell, haben aber kleine Rundungsfehler - runden Sie immer auf etwas Vernünftiges, wenn Sie ihre Ergebnisse anzeigen.

9voto

0,6 * 3 es ist fantastisch!)) Bei mir funktioniert das gut:

function dec( num )
{
    var p = 100;
    return Math.round( num * p ) / p;
}

Sehr, sehr einfach))

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X