Zum Beispiel haben Sie mit dem Dollar niemals eine Genauigkeit von weniger als 0,01 USD
Ja wirklich?
die uralte Frage, warum Sie Währung nicht als Gleitkommazahl nach IEEE 754 speichern sollten.
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 1
Sitzen 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.1
wie 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:
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.