73 Stimmen

Beste Möglichkeit, Währungswerte in C++ zu speichern

Ich weiß, dass ein Float aufgrund von Rundungsfehlern nicht geeignet ist, um Währungswerte zu speichern. Gibt es eine Standardmethode zur Darstellung von Geld in C++?

Ich habe in der Boost-Bibliothek nachgesehen und nichts darüber gefunden. In Java scheint es, dass BigInteger der Weg ist, aber ich konnte kein Äquivalent in C++ finden. Ich könnte meine eigene Geldklasse schreiben, ziehe es aber vor, dies nicht zu tun, wenn es etwas getestet wird.

35voto

Eclipse Punkte 43775

Bewahren Sie es nicht nur als Cents auf, da sich bei der Multiplikation mit Steuern und Zinsen schnell Fehler einschleichen können. Behalten Sie zumindest zwei zusätzliche signifikante Ziffern bei: 12,45 $ würden als 124.500 gespeichert werden. Wenn Sie den Betrag in einer vorzeichenbehafteten 32-Bit-Ganzzahl speichern, können Sie mit 200.000 $ arbeiten (positiv oder negativ). Wenn Sie größere Zahlen oder eine höhere Genauigkeit benötigen, bietet eine Ganzzahl mit Vorzeichen (64 Bit) wahrscheinlich den Platz, den Sie für lange Zeit benötigen.

Es könnte hilfreich sein, diesen Wert in eine Klasse zu verpacken, damit Sie diese Werte an einer Stelle erstellen, mit ihnen rechnen und sie für die Anzeige formatieren können. Damit hätten Sie auch einen zentralen Ort, an dem Sie die Währung, in der der Wert gespeichert wird, angeben können (USD, CAD, EURO, usw.).

30voto

Orion Adrian Punkte 18345

Nachdem ich mich mit diesem Thema in tatsächlichen Finanzsystemen beschäftigt habe, kann ich Ihnen sagen, dass Sie wahrscheinlich eine Zahl mit einer Genauigkeit von mindestens 6 Dezimalstellen verwenden sollten (ausgehend von USD). Da es sich um Währungswerte handelt, werden Sie hier hoffentlich nicht völlig aus dem Ruder laufen. Es gibt Vorschläge für das Hinzufügen von Dezimaltypen zu C++, aber ich weiß nichts von Vorschlägen, die tatsächlich schon verfügbar sind.

Der beste native C++-Typ, den man hier verwenden kann, ist long double.

Das Problem bei anderen Ansätzen, die einfach einen int verwenden, ist, dass Sie mehr als nur Ihre Cents speichern müssen. Oft werden Finanztransaktionen mit nicht-ganzzahligen Werten multipliziert, und das bringt Probleme mit sich, da 100,25 $, übersetzt in 10025 * 0,000123523 (z. B. APR), Probleme verursachen. Irgendwann landet man im Fließkomma-Land, und die Konvertierung wird sehr teuer.

In den meisten einfachen Situationen tritt das Problem nicht auf. Ich gebe Ihnen ein genaues Beispiel:

Wenn Sie mehrere tausend Währungswerte mit einem Prozentsatz multiplizieren und dann addieren, erhalten Sie eine andere Zahl, als wenn Sie die Gesamtsumme mit diesem Prozentsatz multipliziert hätten, wenn Sie nicht genügend Nachkommastellen beibehalten. Das mag in manchen Situationen funktionieren, aber oft liegen Sie dann schnell um mehrere Cent daneben. Meiner allgemeinen Erfahrung nach sollten Sie darauf achten, dass Sie eine Genauigkeit von bis zu 6 Dezimalstellen beibehalten (und sicherstellen, dass die verbleibende Genauigkeit für den ganzzahligen Teil verfügbar ist).

Verstehen Sie auch, dass es keine Rolle spielt, mit welchem Typ Sie es aufbewahren, wenn Sie weniger präzise rechnen. Wenn Sie mit einfacher Genauigkeit rechnen, spielt es keine Rolle, ob Sie die Daten mit doppelter Genauigkeit speichern. Ihre Genauigkeit wird bis zur ungenauesten Berechnung korrekt sein.


Das heißt, wenn Sie nur einfache Additionen oder Subtraktionen durchführen und dann die Zahl speichern, ist alles in Ordnung, aber sobald etwas Komplizierteres auftaucht, bekommen Sie Probleme.

25voto

jblocksom Punkte 13199

Schauen Sie in die relativ neue Intelr Decimal Floating-Point Math Library . Es ist speziell für Finanzanwendungen und implementiert einige der neue Normen für binäre Gleitkommaarithmetik (IEEE 754r) .

15voto

user331471 Punkte 863

Das größte Problem ist die Rundung selbst!

19% von 42,50 € = 8,075 €. Aufgrund der deutschen Rundungsregeln sind dies 8,08 €. Das Problem ist, dass (zumindest auf meinem Rechner) 8,075 nicht als Double dargestellt werden kann. Selbst wenn ich die Variable im Debugger auf diesen Wert ändere, erhalte ich 8,0749999....

Und genau hier versagt meine Rundungsfunktion (und jede andere Fließkomma-Logik, die mir einfällt), denn sie ergibt 8,07 €. Die signifikante Stelle ist 4 und so wird der Wert abgerundet. Und das ist schlichtweg falsch und man kann nichts dagegen tun, es sei denn, man vermeidet die Verwendung von Fließkommazahlen, wo immer es möglich ist.

Es funktioniert gut, wenn Sie 42,50 € als Integer 42500000 darstellen.

42500000 * 19 / 100 = 8075000. Jetzt können Sie die Rundungsregel über 8080000 anwenden. Dieser Wert kann aus Darstellungsgründen leicht in einen Währungswert umgewandelt werden. 8,08 €.

Aber ich würde das immer in einen Kurs verpacken.

9voto

Piotr Punkte 211

Sie können den dezimalen Datentyp ausprobieren:

https://github.com/vpiotr/decimal_for_cpp

Entwickelt für die Speicherung von geldbezogenen Werten (Geldsaldo, Währungskurs, Zinssatz), benutzerdefinierte Genauigkeit. Bis zu 19 Ziffern.

Es ist eine reine Header-Lösung für C++.

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