Sie sollten Ihre Dezimalwerte wahrscheinlich um 100 skalieren und alle Geldwerte in ganzen Cent darstellen. Dies dient dazu, Probleme mit der Gleitkomma-Logik und der Arithmetik zu vermeiden . In JavaScript gibt es keinen dezimalen Datentyp - der einzige numerische Datentyp ist Gleitkomma. Daher wird allgemein empfohlen, Geld als 2550
Cent anstelle von 25.50
Dollar zu behandeln.
Beachten Sie Folgendes in JavaScript:
var result = 1.0 + 2.0; // (result === 3.0) returns true
Aber:
var result = 0.1 + 0.2; // (result === 0.3) returns false
Der Ausdruck 0.1 + 0.2 === 0.3
kehrt zurück false
, aber glücklicherweise ist die Ganzzahlarithmetik im Gleitkomma genau, sodass Dezimaldarstellungsfehler durch Skalieren von 1 vermieden werden können .
Beachten Sie, dass während die Menge der reellen Zahlen unendlich ist, nur eine endliche Anzahl von ihnen (18.437.736.874.454.810.627, um genau zu sein) genau durch das JavaScript-Gleitkommaformat dargestellt werden kann. Daher ist die Darstellung der anderen Zahlen eine Annäherung an die tatsächliche Zahl 2 .
1 Douglas Crockford: JavaScript: Die guten Teile : Anhang A - Schreckliche Teile (Seite 105) .
2 David Flanagan: JavaScript: The Definitive Guide, 4. Ausgabe : 3.1.3 Gleitkomma-Literale (Seite 31) .
3000.57 + 0.11 === 3000.68
kehrtfalse
.Es ist die Lösung, jeden Wert mit 100 zu skalieren. Es ist wahrscheinlich nutzlos, es von Hand zu machen, da Sie Bibliotheken finden können, die das für Sie tun. Ich empfehle moneysafe, das eine funktionale API bietet, die sich gut für ES6-Anwendungen eignet:
https://github.com/ericelliott/moneysafe
Funktioniert sowohl in Node.js als auch im Browser.
quelle
in$, $
sind für jemanden mehrdeutig, der das Paket zuvor nicht verwendet hat. Ich weiß, es war Erics Entscheidung, die Dinge so zu benennen, aber ich denke immer noch, dass es ein Fehler genug ist, dass ich sie wahrscheinlich in der import / destructured require-Anweisung umbenennen würde.Money$afe has not yet been tested in production at scale.
. Ich möchte nur darauf hinweisen, damit jeder überlegen kann, ob dies für seinen Anwendungsfall geeignet istEs gibt keine "präzise" Finanzberechnung wegen nur zwei Dezimalbruchstellen, aber das ist ein allgemeineres Problem.
In JavaScript können Sie jeden Wert um 100 skalieren und jedes Mal verwenden,
Math.round()
wenn ein Bruch auftreten kann.Sie können ein Objekt verwenden, um die Zahlen zu speichern und die Rundung in die Prototypenmethode aufzunehmen
valueOf()
. So was:Auf diese Weise wird jedes Mal, wenn Sie ein Money-Objekt verwenden, es auf zwei Dezimalstellen gerundet dargestellt. Der ungerundete Wert ist weiterhin über erreichbar
m.amount
.Money.prototype.valueOf()
Wenn Sie möchten , können Sie Ihren eigenen Rundungsalgorithmus einbauen .quelle
Money(0.1)
bedeutet, dass der JavaScript-Lexer die Zeichenfolge "0.1" aus der Quelle liest und sie dann in einen binären Gleitkomma konvertiert und Sie dann bereits eine unbeabsichtigte Rundung durchgeführt haben. Das Problem ist die Darstellung (binär oder dezimal), nicht die Genauigkeit .benutze decimaljs ... Es ist eine sehr gute Bibliothek, die einen harten Teil des Problems löst ...
Verwenden Sie es einfach in Ihrem gesamten Betrieb.
https://github.com/MikeMcl/decimal.js/
quelle
Ihr Problem beruht auf Ungenauigkeiten bei Gleitkommaberechnungen. Wenn Sie nur das Runden verwenden, um dies zu lösen, treten beim Multiplizieren und Dividieren größere Fehler auf.
Die Lösung ist unten, eine Erklärung folgt:
Sie müssen über die Mathematik dahinter nachdenken, um sie zu verstehen. Reelle Zahlen wie 1/3 können in der Mathematik nicht mit Dezimalwerten dargestellt werden, da sie endlos sind (z. B. - .333333333333333 ...). Einige Dezimalzahlen können nicht korrekt binär dargestellt werden. Beispielsweise kann 0.1 mit einer begrenzten Anzahl von Ziffern nicht korrekt binär dargestellt werden.
Eine ausführlichere Beschreibung finden Sie hier: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
Schauen Sie sich die Lösungsimplementierung an: http://floating-point-gui.de/languages/javascript/
quelle
Aufgrund der binären Natur ihrer Codierung können einige Dezimalzahlen nicht mit perfekter Genauigkeit dargestellt werden. Beispielsweise
Wenn Sie reines Javascript verwenden müssen, müssen Sie für jede Berechnung über eine Lösung nachdenken. Für den obigen Code können wir Dezimalstellen in ganze Ganzzahlen konvertieren.
Vermeiden von Problemen mit Dezimalmathematik in JavaScript
Es gibt eine spezielle Bibliothek für Finanzberechnungen mit hervorragender Dokumentation. Finance.js
quelle
Leider ignorieren alle bisherigen Antworten die Tatsache, dass nicht alle Währungen 100 Untereinheiten haben (z. B. ist der Cent die Untereinheit des US-Dollars (USD)). Währungen wie der Irakische Dinar (IQD) haben 1000 Untereinheiten: Ein Irakischer Dinar hat 1000 Dateien. Der japanische Yen (JPY) hat keine Untereinheiten. "Mit 100 multiplizieren, um eine ganzzahlige Arithmetik durchzuführen" ist also nicht immer die richtige Antwort.
Zusätzlich müssen Sie für Geldberechnungen die Währung im Auge behalten. Sie können einer indischen Rupie (INR) keinen US-Dollar (USD) hinzufügen (ohne zuvor einen in den anderen umzurechnen).
Es gibt auch Einschränkungen hinsichtlich der maximalen Menge, die durch den ganzzahligen Datentyp von JavaScript dargestellt werden kann.
Bei Geldberechnungen müssen Sie auch berücksichtigen, dass Geld eine endliche Genauigkeit hat (normalerweise 0-3 Dezimalstellen) und die Rundung auf bestimmte Weise erfolgen muss (z. B. "normale" Rundung im Vergleich zur Bankrundung). Die Art der durchzuführenden Rundung kann auch je nach Gerichtsbarkeit / Währung variieren.
Der Umgang mit Geld in Javascript hat eine sehr gute Diskussion der relevanten Punkte.
Bei meinen Suchen habe ich die Bibliothek dinero.js gefunden , die viele Probleme bei Geldberechnungen behandelt . Ich habe es noch nicht in einem Produktionssystem verwendet und kann daher keine fundierte Meinung dazu abgeben.
quelle