Wir haben kürzlich ein System implementiert, das Werte in mehreren Währungen verarbeiten und zwischen ihnen umrechnen muss, und einige Dinge auf die harte Tour herausgefunden.
NIEMALS SCHWIMMENDE PUNKTNUMMERN FÜR GELD VERWENDEN
Gleitkomma-Arithmetik führt zu Ungenauigkeiten, die möglicherweise erst bemerkt werden, wenn sie etwas vermasselt haben. Alle Werte sollten entweder als Ganzzahlen oder als Typen mit festen Dezimalstellen gespeichert werden. Wenn Sie sich für die Verwendung eines Typs mit festen Dezimalstellen entscheiden, stellen Sie sicher, dass Sie genau verstehen, was dieser Typ unter der Haube tut (dh intern eine Ganzzahl oder einen Gleitkomma verwendet Art).
Wenn Sie Berechnungen oder Konvertierungen durchführen müssen:
- Konvertieren Sie Werte in Gleitkommawerte
- Neuen Wert berechnen
- Runden Sie die Zahl und konvertieren Sie sie zurück in eine Ganzzahl
Wenn Sie eine Gleitkommazahl in Schritt 3 wieder in eine Ganzzahl konvertieren, wandeln Sie sie nicht einfach um - verwenden Sie eine mathematische Funktion, um sie zuerst zu runden. Dies wird normalerweise sein round
, obwohl es in besonderen Fällen sein könnte floor
oder ceil
. Kennen Sie den Unterschied und wählen Sie sorgfältig.
Speichern Sie den Typ einer Zahl neben dem Wert
Dies ist für Sie möglicherweise nicht so wichtig, wenn Sie nur eine Währung abwickeln, aber für uns war es wichtig, mehrere Währungen abzuwickeln. Wir haben den dreistelligen Code für eine Währung wie USD, GBP, JPY, EUR usw. verwendet.
Je nach Situation kann es auch hilfreich sein, Folgendes zu speichern:
- Ob die Nummer vor oder nach Steuern ist (und wie hoch der Steuersatz war)
- Ob die Zahl das Ergebnis einer Konvertierung ist (und woraus sie konvertiert wurde)
Kennen Sie die Genauigkeitsgrenzen der Zahlen, mit denen Sie es zu tun haben
Für reale Werte möchten Sie so genau sein wie die kleinste Einheit der Währung. Dies bedeutet, dass Sie keine Werte haben, die kleiner als ein Cent, ein Penny, ein Yen, ein Fen usw. sind. Speichern Sie Werte nicht ohne Grund mit höherer Genauigkeit.
Intern können Sie sich für kleinere Werte entscheiden. In diesem Fall handelt es sich um eine andere Art von Währungswert . Stellen Sie sicher, dass Ihr Code weiß, welcher welcher ist, und dass er sie nicht verwechselt. Vermeiden Sie auch hier die Verwendung von Gleitkommawerten.
Wenn wir all diese Regeln zusammenfassen, haben wir uns für die folgenden Regeln entschieden. Im laufenden Code werden Währungen mit einer Ganzzahl für die kleinste Einheit gespeichert.
class Currency {
String code; // eg "USD"
int value; // eg 2500
boolean converted;
}
class Price {
Currency grossValue;
Currency netValue;
Tax taxRate;
}
In der Datenbank werden die Werte als Zeichenfolge im folgenden Format gespeichert:
USD:2500
Das speichert den Wert von 25,00 $. Dies war nur möglich, weil sich der Code, der sich mit Währungen befasst, nicht in der Datenbankebene selbst befinden muss, sodass alle Werte zuerst in den Speicher konvertiert werden können. Andere Situationen eignen sich zweifellos für andere Lösungen.
Und falls ich es vorher nicht klar gemacht habe, benutze keinen Float!