Kann Java nicht rechnen ?

Hi all,
habe ein Problem. wenn ich folgendes rechnen lasse erhalte ich
Mist:

Double Ergebnis = 32.3 * 100;
System.out.print(Ergebnis);

Richtig wäre 3230.0 es ist aber 3229.9999999999995 !!!

Warum was mache ich falsch ? Wenn ich es in ein (int) caste ist
der Fehler noch grösser (3229)! Bei anderen Zahlen passiert das
nicht warum bei 32.3 ? Ist es ein Bug oder rechnet er
relativistisch oder so was ?

Vielen Dank!

Dirk

Double Ergebnis = 32.3 * 100;
System.out.print(Ergebnis);

Richtig wäre 3230.0 es ist aber 3229.9999999999995 !!!

Korrekt - und das ist in den meisten Programmiersprachen so.

Warum was mache ich falsch ?

Du? Nichts. Java aber auch nicht. Fließkommazahlen werden nur mit einer bestimmten Genauigkeit berechnet, das ist alles.

Wenn ich es in ein (int) caste
ist
der Fehler noch grösser (3229)!

Weil da grundsätzlich abgeschnitten wird, hier also satte 0.99999999… wegfallen. Runden (Klasse Math) ist hier angebrachter.

Bei anderen Zahlen passiert
das
nicht warum bei 32.3 ?

Weil das in Binärschreibweise wohl eine sehr krumme Zahl ist, vielleicht periodisch, so wie 0.01 z.B. (furchtbare Zahl!) Hast du schonmal versucht, 1.000.000 Pfennige als float zu addieren? Sehr lustiges Ergebnis …

Ist es ein Bug oder rechnet er
relativistisch oder so was ?

Nein. Weder noch.

Wenn du mehr Genauigkeit brauchst, dann benutze entweder Festkommazahlen (sprich: Integer/Long, z.B. für Währungen, die ja immer nur eine feste Nachkommastellenzahl haben), bei denen z.B. alle Zahlen mit 100 multipliziert und gerundet als Ganzzahlen benutzt werden, oder schau dir die Klassen in java.math.* an.

Gruß,
Stefan :smile:

Danke! Dachte schon ich könnte nicht rechnen

Wenn du mehr Genauigkeit brauchst, dann benutze entweder
Festkommazahlen (sprich: Integer/Long, z.B. für Währungen, die
ja immer nur eine feste Nachkommastellenzahl haben), bei denen
z.B. alle Zahlen mit 100 multipliziert und gerundet als
Ganzzahlen benutzt werden, oder schau dir die Klassen in
java.math.* an.

Ich brauche es als Währungsrechner 0.01 Cent. Aber ich muss auch
100 000 000 000 Euro darstellen also 100 000 000 000 000 0 Cent/100 und das Ganze dann wieder in Euro darstellen !

Habe es nun mit:

long Ergebnis = (long) Math.ceil(32.2 * 100);

gelöst.

Danke, für die Erklärung.
Dirk

Wieder hallo!

Habe es nun mit:
long Ergebnis = (long) Math.ceil(32.2 * 100);
gelöst.

Das hilft dir in diesem Fall. Leider können aber auch Genauigkeitsfehler nach oben hin auftreten, so dass deine Methode in diesem Fall auch gerne mal 0.9999999 dazu addieren kann!

Nimm doch

long ergebnis = Math.round((double) 32.2 \* (double) 100);

dann solltest du einigermaßen im sicheren Bereich sein…

Ich brauche es als Währungsrechner 0.01 Cent. Aber ich muss
auch
100 000 000 000 Euro darstellen also 100 000 000 000 000 0
Cent/100 und das Ganze dann wieder in Euro darstellen !

Wie schon erwähnt: Wer Währungen in double (oder sogar float!) ausdrückt, gehört eigentlich vors Informatikergericht.

Für Währungswerte nehme ich grundsätzlich long, multipliziert mit - je nachdem - 100, 1000 oder (selten) auch noch mehr, je nachdem, wie genau ich es brauche. Des Euros wegen habe ich neulich mal sechs Stellen genommen (195583), aber wie gesagt: Das ist die Ausnahme.

Mit solchen Festkommazahlen kannst du problemlos rechnen (addieren, subtrahieren und mit normalen Zahlen multiplizieren) und verlierst keine Genauigkeit durch Fließkommarechenfehler. Fließkommazahlen sind für Währungen genauso unnötig wie risikoreich.

Am schönsten verpackt mensch sowas ohnehin in eine eigene Klasse und rechnet dann damit (der Currency-Datentyp existiert ja erst im Beta-JDK 1.4). Dann bleibt der Faktor in der Klasse drin, die Berechnungen auch - und am Besten auch noch gleich die Formatierung (notfalls mit einem DateFormat als Parameter). So kannst du sicherstellen, dass
a) der Faktor nie außerhalb der Klasse geändert werden muss,
b) sich niemand außerhalb der Klasse um Festkommazahlen kümmern muss
c) du immer genaue Währungsberechnungen ausführen kannst, ohne zusätzlichen Aufwand im Programm.

Am Besten versteckst du das Ganze noch hinter einem Interface, um auf einfache Art und Weise verschieden genaue Klassen verwenden zu können, etc. pp.

Na ja, mal wieder vom 100. ins 1000. …

Egal, ich wollte ja nur sicher sein, dass du auch weißt, was du da tust :smile:

Lieben Gruß,
Stefan

1 „Gefällt mir“

Hi.
Schonmal überlegt, ob es nicht sinnvoller wäre, statt double die Klasse BigDecimal (gehört zu java.math, glaube ich) einzusetzen? Die rechnet genauer.
CU,
Sebastian.