Gibt es eine einzige Datendarstellung, die für alle Währungen funktioniert (auch für diejenigen, die sich von Dollar, Euro und Pfund unterscheiden)?


12

Ich kann viele Fragen zu Bibliotheken finden, mit denen Beträge in einer bestimmten Währung dargestellt werden können. Und über die uralte Frage, warum Sie keine Währung als Gleitkommazahl nach IEEE 754 speichern sollten. Aber ich kann anscheinend nichts mehr finden. Sicher gibt es viel mehr zu wissen über die Verwendung von Währungen in der realen Welt. Ich interessiere mich besonders für das, was Sie wissen müssen, um es im physischen Gebrauch darzustellen (z. B. mit dem Dollar haben Sie nie eine Genauigkeit von weniger als 0,01 US-Dollar, was die Darstellung als ganze Zahl von Cent ermöglicht).

Es ist jedoch schwierig, Annahmen darüber zu treffen, wie vielseitig Ihr Programm ist, wenn Sie nur die populären westlichen Währungen kennen (wie Dollar, Euro und Pfund). Was ist sonst relevantes Wissen in einer rein programmatischen Perspektive? Ich mache mir keine Sorgen um das Thema Bekehrung.

Was müssen wir insbesondere wissen, um Werte in einer bestimmten Währung speichern und ausdrucken zu können?


2
Nicht alle Programmierer arbeiten in Branchen, in denen Währungsbeträge manipuliert werden.
Whatsisname

4
Ja natürlich. Aber das kann zu fast allem gesagt werden. Ich denke, wir können davon ausgehen, dass diejenigen, die diese Frage nützlich finden, mit der Währung arbeiten.
Kat

5
Ich habe viel Entwicklungsarbeit für Banken und andere Finanzdienstleister in NYC geleistet. Und ich kann Ihnen so ziemlich garantieren, dass Ihre Frage nicht in "geschlossener Form" beantwortet wird. Sie könnten genauso gut fragen: "Wie viel Mathe muss ich wissen?" Zum Beispiel gingen die Aktienkurse in den 1990er Jahren von Achtel und 256er auf Dezimal und erforderten viele Neuprogrammierungen. Wer hätte das gedacht? Sie müssen nur wissen, welches Geschäft Ihre Anwendungen unterstützen und wie Sie die Daten (in diesem Fall die Währung) am besten darstellen, um diese Geschäftsanforderungen zu erfüllen.
John Forkosh

4
Mein 0.02: Preis ist eine Sache. Die Währung ist eine andere.
Machado

3
Ich dachte: Oh, es muss einen gemeinsamen Nenner für alle Währungen geben. Aber vielleicht auch nicht. Das Pfund Sterling ist derzeit 1⁄100 Pfund, war aber 1⁄240 Pfund. Sie haben also nicht nur eine Division von 1/240, sondern auch ein Umschaltdatum und möglicherweise einen Wechselkurs für alte Pence, der noch nicht umgeschaltet wurde. en.wikipedia.org/wiki/Penny_sterling Lass mich noch nicht mal mit Kaurimuscheln anfangen! en.wikipedia.org/wiki/Shell_money oder die Tatsache, dass Geld Glauben erfordert, um real zu werden: en.wikipedia.org/wiki/Money Gute Frage, auch wenn es nicht gut zu StackExchange passt!
GlenPeterson

Antworten:


24

Zum Beispiel haben Sie mit dem Dollar niemals eine Genauigkeit von weniger als 0,01 USD

Ja wirklich? Bildbeschreibung hier eingeben

die uralte Frage, warum Sie Währung nicht als Gleitkommazahl nach IEEE 754 speichern sollten.

Bildbeschreibung hier eingeben

Sie können Zoll auch in IEEE 754- Gleitkommazahlen speichern . Sie speichern genau so, wie Sie es erwarten würden.

Sie können beliebig viel Geld in IEEE 754- Gleitkommazahlen speichern, die Sie mithilfe der Häkchen speichern können, die ein Lineal in Bruchteile eines Zolls teilen.

Warum? Denn wenn Sie IEEE 754 verwenden , speichern Sie es so.

Die Sache mit Zoll ist, dass sie in zwei Hälften geteilt sind. Das Wichtigste an den meisten Währungen ist, dass sie in Zehntel unterteilt sind (einige Arten sind es nicht, aber lassen Sie uns konzentriert bleiben).

Dieser Unterschied wäre nicht allzu verwirrend, außer dass für die meisten Programmiersprachen die Ein- und Ausgabe von IEEE 754 erfolgt Gleitkommazahlen in Dezimalzahlen ausgedrückt wird! Das ist sehr seltsam, weil sie nicht in Dezimalzahlen gespeichert sind.

Aus diesem Grund kann man nie sehen, wie die Bits seltsame Dinge tun, wenn man den Computer zum Speichern auffordert0.1 . Sie sehen die Verrücktheit nur, wenn Sie dagegen rechnen und es hat seltsame Fehler.

Aus Josh Blochs effektivem Java :

System.out.println(1.03 - .42);

Produziert 0.6100000000000001

Was am meisten darüber aussagt, ist nicht das 1Sitzen dort rechts. Es sind die seltsamen Zahlen, die verwendet werden mussten, um es zu bekommen. Anstatt das beliebteste Beispiel zu verwenden,0.1 müssen wir ein Beispiel verwenden, das das Problem zeigt und die Rundung vermeidet, die es verbergen würde.

Warum funktioniert das zum Beispiel?

System.out.println(.01 - .02);

Produziert -0.01

Weil wir Glück hatten.

Ich hasse Probleme, die schwer zu diagnostizieren sind, weil ich manchmal "Glück" habe.

IEEE 754 kann 0.1 einfach nicht genau speichern. Aber wenn Sie ihn auffordern, 0.1 zu speichern und dann zum Drucken aufzufordern, wird 0.1 angezeigt und Sie werden denken, dass alles in Ordnung ist. Es ist nicht in Ordnung, aber das kann man nicht sehen, weil es rundet, um wieder auf 0.1 zu kommen.

Manche Leute verwechseln andere, indem sie diese Diskrepanzen als Rundungsfehler bezeichnen. Nein, das sind keine Rundungsfehler. Das Runden macht, was es soll, und verwandelt, was keine Dezimalstelle ist, in eine Dezimalstelle, damit es auf dem Bildschirm gedruckt werden kann.

Dadurch wird jedoch die Diskrepanz zwischen der Anzeige und der Speicherung der Nummer ausgeblendet. Der Fehler ist bei der Rundung nicht aufgetreten. Es geschah, als Sie beschlossen, eine Zahl in ein System einzufügen, das sie nicht genau speichern kann, und davon ausgegangen sind, dass sie genau dann gespeichert wird, wenn dies nicht der Fall ist.

Niemand erwartet, dass π genau in einem Taschenrechner gespeichert wird, und es gelingt ihm, einwandfrei damit zu arbeiten. Das Problem besteht also nicht einmal in der Präzision. Es geht um die erwartete Präzision. Computer zeigen ein Zehntel so an 0.1wie unsere Taschenrechner, daher erwarten wir, dass sie ein Zehntel so perfekt speichern wie unsere Taschenrechner. Sie tun es nicht. Was überrascht, da Computer teurer sind.

Lassen Sie mich Ihnen die Nichtübereinstimmung zeigen:

Bildbeschreibung hier eingeben

Beachten Sie, dass 1/2 und 0,5 perfekt ausgerichtet sind. Aber 0.1 passt einfach nicht zusammen. Sicher können Sie näher kommen, wenn Sie durch 2 teilen, aber Sie werden es nie genau treffen. Und wir brauchen jedes Mal mehr Bits, wenn wir durch 2 dividieren. Für die Darstellung von 0,1 bei jedem System, das durch 2 dividiert, ist eine unendliche Anzahl von Bits erforderlich. Meine Festplatte ist einfach nicht so groß.

Also 754 IEEE stoppt versuchen , wenn es von Bits abläuft. Das ist schön, denn ich brauche Platz auf meiner Festplatte für ... Familienfotos. Nicht wirklich. Familienfotos. : P

Wie auch immer, was Sie eingeben und was Sie sehen, sind die Dezimalstellen (rechts), aber was Sie speichern, sind die Bikimalstellen (links). Manchmal sind die vollkommen gleich. Manchmal sind sie nicht. Manchmal SIEHT es so aus, als wären sie gleich, wenn sie es einfach nicht sind. Das ist die Rundung.

Was müssen wir insbesondere wissen, um Werte in einer bestimmten Währung speichern und ausdrucken zu können?

Wenn Sie mit meinem dezimalbasierten Geld umgehen, verwenden Sie bitte keine Floats oder Doubles.

Wenn Sie sicher sind, dass Dinge wie zehntel Pennies nicht betroffen sind, dann lagern Sie nur Pennies. Wenn Sie dies nicht tun, ermitteln Sie die kleinste Einheit dieser Währung und verwenden Sie diese. Wenn Sie nicht können, verwenden Sie so etwas wie BigDecimal .

Mein Vermögen wird wahrscheinlich immer in eine 64-Bit-Ganzzahl passen, aber Dinge wie BigInteger funktionieren gut für Projekte, die größer sind. Sie sind nur langsamer als einheimische Typen.

Herauszufinden, wie man es aufbewahrt, ist nur das halbe Problem. Denken Sie daran, dass Sie es auch anzeigen können müssen. Ein gutes Design wird diese beiden Dinge trennen. Das eigentliche Problem bei der Verwendung von Schwimmern ist, dass diese beiden Dinge miteinander verfilzt sind.

Bildbeschreibung hier eingeben


6
Ich habe nicht wirklich nach einer weiteren Erklärung gesucht, warum IEEE 754 nicht für Geld funktioniert. Ich erwähnte im OP, dass dies an anderer Stelle gut erklärt wurde. Ebenso gibt es einen Grund, warum ich den Begriff "physische Nutzung" verwendet habe. Denn während die Gaspreise, Börsenwerte usw. eine willkürliche Genauigkeit aufweisen können, geht das physische Geld (und die große Anzahl von Benutzertransaktionen) nicht über die Hunderte hinaus (und verschiedene Software-Teile möchten nur das darstellen, womit bezahlt werden kann) physisches Geld). Eine Information, die ich mich fragte, war, ob es Währungen gab, die mehr Dezimalstellen aufwiesen.
Kat

3
Die "Verrücktheit" des Gleitkommas ist nicht nur auf die Halbwertszeit gegenüber der Zehntelwertszeit beschränkt. Der "Gleitkomma" -Aspekt im Namen führt auch manchmal zu unerwarteten Ergebnissen.
Whatsisname

6
Vor der Dezimalisierung lautete die britische Währung Pfund, Schilling und Pence (£ sd), mit £ 1 == 20s, 1s = 12d, also £ 1 = 240d, also 1d = 0,0046666666666. Sie konnte nicht einmal als Dezimalzahl dargestellt werden. Vor dem Beitritt zum Euro notierte die italienische Lira bei 2346,4 (im Jahr 2001) gegenüber dem US-Dollar. So stießen beispielsweise Gehälter und Immobilienpreise manchmal an die Obergrenze von Schwebepositionen mit einfacher Genauigkeit, und die Wirtschaftszahlen erreichten das obere Niveau von Doppelwerten.
Steve Barnes

2
Ich möchte nur argumentieren / darauf hinweisen, dass die Währung eine Sache ist und der Preis eine andere Sache. Die Preise können mit einer Genauigkeit von mehr als 0,01 USD angegeben werden, mit dieser Genauigkeit können Sie jedoch nicht effektiv bezahlen.
Machado

1
Auch Familienfotos . Pft. :)
Machado

10

Ich kann viele Fragen zu Bibliotheken finden, mit denen Beträge in einer bestimmten Währung dargestellt werden können.

"Bibliotheken" sind nicht erforderlich, es sei denn, die Standardbibliothek Ihrer Sprache enthält bestimmte Datentypen, wie ich noch erläutern werde.

Sicherlich gibt es viel mehr zu wissen über die Verwendung von Währungen in der realen Welt. Ich interessiere mich besonders für das, was Sie wissen müssen, um es im physischen Gebrauch darzustellen (z. B. mit dem Dollar haben Sie nie eine Genauigkeit von weniger als 0,01 US-Dollar, was die Darstellung als ganze Zahl von Cent ermöglicht).

Ganz einfach, Sie brauchen eine Festkommadezimalzahl , keine Gleitkommadezimalzahl . Beispielsweise könnte die BigDecimal- Klasse von Java zum Speichern eines Währungsbetrags verwendet werden. Andere moderne Sprachen verfügen über ähnliche integrierte Typen, einschließlich C # und Python . Die Implementierungen variieren, sie speichern jedoch normalerweise eine Zahl als Ganzzahl mit der Dezimalstelle als separatem Datenelement. Dies ergibt eine genaue Genauigkeit, selbst wenn eine Arithmetik ausgeführt wird, die ungerade Reste (z. B. 0,0000001) mit IEEE-Gleitkommazahlen ergeben würde.

Was müssen wir insbesondere wissen, um Werte in einer bestimmten Währung speichern und ausdrucken zu können?

Es gibt einige wichtige Punkte.

  1. Verwenden Sie einen tatsächlichen Dezimaltyp anstelle eines Gleitkommas.

  2. Verstehen Sie, dass ein Währungsbetrag aus zwei Komponenten besteht: einem Wert (5,63) und einem Währungscode oder -typ (USD, CAD, GBP, EUR usw.). Manchmal können Sie den Währungscode ignorieren, manchmal ist es wichtig. Was ist, wenn Sie an einem Finanz- oder Einzelhandels- / E-Commerce-System arbeiten, das mehrere Währungen zulässt? Was passiert, wenn Sie versuchen, einem Kunden Geld in CAD abzunehmen, dieser aber mit MXN bezahlen möchte? Sie benötigen einen "Geld" -Typ mit einem Währungscode und einem Währungsbetrag, um diese Werte mischen zu können (auch Wechselkurs, aber ich möchte mit einer Tangente nicht zu weit kommen). Gleichzeitig muss sich meine persönliche Finanzsoftware darüber keine Gedanken machen, da alles in USD lautet (es kann Währungen mischen, aber ich muss es nie).

  3. Während eine Währung in der Praxis möglicherweise die kleinste physische Einheit hat (CAD und USD haben Cent, JPY ist nur ... Yen), ist es möglich, kleiner zu werden. In der Antwort von CandiedOrange werden die Kraftstoffpreise in Zehntel Cent angegeben. Meine Grundsteuern werden als Mühlen pro Dollar oder Zehntel Cent (1/1000 eines USD-Dollars) veranschlagt. Beschränken Sie sich nicht auf 0,01 USD. Während Sie diese Werte möglicherweise die meiste Zeit anzeigen , sollten Ihre Typen kleinere zulassen (die oben genannten Dezimaltypen).

  4. Zwischenberechnungen müssen mit Sicherheit präziser sein als ein Cent. Ich habe an Einzelhandels- / E-Commerce-Systemen gearbeitet, bei denen interne Werte intern auf 0,00000001 US-Dollar gerundet wurden. Unendliche Genauigkeit wird normalerweise nicht von Dezimaltypen (oder SQL) unterstützt, daher muss es eine gewisse Beschränkung geben. Wenn Sie beispielsweise 1/3 mit Javas BigDecimal teilen, wird eine Ausnahme ohne RoundingMode oder MathContext ausgelöst, da der Wert nicht genau dargestellt werden kann.

    Dies ist jedoch in bestimmten Fällen kritisch. Nehmen wir an, Sie haben einen Benutzer mit sechs Artikeln im Warenkorb und er geht zur Kasse. Ihr System muss Steuern berechnen, und zwar pro Artikel, da Artikel möglicherweise anders besteuert werden. Wenn Sie die Steuern für jeden Artikel aufrunden, kann es zu Rundungsfehlern auf Transaktions- / Wagenebene kommen. Ein Ansatz, um dies zu beheben, könnte darin bestehen, Steuern auf mehr Dezimalstellen pro Artikel zu speichern, die Gesamtsumme für die gesamte Transaktion abzurufen und jeden Artikel zu runden, damit die Gesamtsteuer korrekt ist (möglicherweise rundet ein Artikel auf, ein anderer ab).

Das Wichtigste dabei ist, dass für die richtigen Leute etwas so Wichtiges wie das Runden von Pfennigen sehr wichtig sein kann (z. B. einige meiner früheren Kunden, die die staatlichen Umsatzsteuern im Namen ihrer Kunden zahlen mussten). Dies sind jedoch alles gelöste Probleme. Behalten Sie die obigen Punkte im Hinterkopf und experimentieren Sie selbst, und Sie werden lernen, indem Sie dies tun.


Am 2. denke ich, Wechselkurs ist genug von einer Sache, um zumindest eine eigene Zahl zu bekommen. Sie müssen berücksichtigen, dass sich die Raten im Laufe der Zeit ändern, was sich auf verschiedene Arten auswirkt.
Izkata

2
+1. Auch Währungen ändern sich im Laufe der Zeit. In Brasilien hatten wir in den 80er und 90er Jahren wiederholt Währungsänderungen, die Nullen senkten und die Währung umbenannten, wenn dies aufgrund der außer Kontrolle geratenen Inflation erforderlich war. Das bedeutet, dass sich jeder Aspekt einer Währung im Laufe der Zeit ändern kann.
Machado

@ Izkata sicherlich habe ich an Systemen gearbeitet, die Währungen ändern. Ich wollte das Thema ansprechen, da es relevant ist. Dies ist jedoch nicht der Schwerpunkt der Frage, und ich könnte wahrscheinlich eine andere Antwort eingeben, solange sich diese mit dem Thema Währungsumtausch befasst.

"Bibliotheken" sind nicht erforderlich, es sei denn, die Standardbibliothek Ihrer Sprache enthält bestimmte Datentypen, wie ich noch erläutern werde. " Währungen können Hälften, Viertel, Zehntel, Achtel usw. haben, was bedeutet, dass wir mindestens eine Dezimaldarstellung für sie benötigen. Aber sind wir völlig sicher, dass es keine Währungen mit einem Drittel des ganzen Stücks gibt?
Daniel McLaury

4

Ein Ort, an dem viele Entwickler mit einer einzigen Datendarstellung für jede Währung konfrontiert sind, sind In-App-Käufe für iOS-Anwendungen. Ihr Kunde kann mit einem Geschäft in nahezu jedem Land der Welt verbunden sein. In diesem Fall erhalten Sie einen Kaufpreis, der aus einer doppelten Genauigkeitszahl und einem Währungscode besteht.

Sie müssen sich bewusst sein, dass die Zahlen groß sein können. Es gibt Währungen, in denen der Gegenwert von beispielsweise zehn Dollar mehr als 100.000 Einheiten beträgt. Und wir sind froh, dass es derzeit keine Währungen wie den simbabwischen Dollar gibt, in denen Sie hundert Billionen Banknoten haben könnten!

Für die Anzeige von Währungen benötigen Sie eine Bibliothek - Sie haben keine Chance, alles selbst in Ordnung zu bringen. Die Anzeige hängt von zwei Faktoren ab: dem Währungscode und dem Gebietsschema des Benutzers. Stellen Sie sich vor, wie US-Dollar und kanadische Dollar mit einem US-Gebietsschema und einem kanadischen Gebietsschema angezeigt werden: In den USA haben Sie $ vs CAN $ und in Kanada haben Sie US $ vs $. Ich hoffe, das ist in das Betriebssystem integriert, oder Sie haben eine gute Bibliothek.

Bei Berechnungen endet jede Berechnung mit einem Rundungsschritt. Sie müssen herausfinden, wie Sie diese Rundung legal durchführen müssen . Das ist kein Programmierproblem, sondern ein rechtliches Problem. Wenn Sie beispielsweise die Mehrwertsteuer in Großbritannien berechnen, müssen Sie die Steuer pro Artikel oder pro Artikelzeile berechnen und auf Cent abrunden. Worauf Sie runden, hängt von der Währung ab. Aber die Regeln hängen natürlich vom Land ab. Sie können nicht erwarten, dass eine in Großbritannien rechtlich korrekte Berechnung in Japan rechtlich korrekt ist und umgekehrt.


0

Was müssen wir insbesondere wissen, um Werte in einer bestimmten Währung speichern und ausdrucken zu können?

  • "zum Speichern von Werten" : ein Festkomma-Datentyp und ein Währungstyp. Ich denke, das ist ziemlich offensichtlich. Das Speichern auf eine nicht festgelegte Zahl kann eine Rundung und eine Änderung des Werts erfordern. Währungsberechnung wäre ein anderes Thema.
  • "um sie auszudrucken" : Gebietsschema des Benutzers. Wenn Sie Glück haben, können Sie mit der Standardbibliothek alles erledigen, z. B. Währungssymbol, Tausendertrennzeichen, Dezimaltrennzeichen, Genauigkeit usw.

Einige Beispielprobleme im Zusammenhang mit dem Gebietsschema:

  • 100 USD in US-Gebietsschema sollten 100,00 USD sein, in einem anderen Gebietsschema mit Punkt als Dezimaltrennzeichen 100,00 USD.
  • In einigen Ländern werden unzählige anstelle von Tausend verwendet, um Nummern zu gruppieren, z. B. statt 10.000,00 nur 1.0000,00
  • Aus praktischen Gründen drucken die Leute nicht alle Zahlen für kleine Währungen, z. B. statt 1.000.000.000,00 USD, sondern nur 1 Milliarde USD.

Ein weiteres mögliches Problem ist, dass die Währung möglicherweise in Gleitkommazahlen konvertiert werden muss, auch wenn Sie sie korrekt in Festkommazahlen speichern, da die zum Drucken verwendete Bibliothek nur Gleitkommazahlen unterstützt.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.