Java rechnet falsch

Durch Zufall bin ich auf einen Fehler in Java gestoßen, der sowohl unter Windows als auch unter Linux auftritt. Die Anweisung

In Pocket speichern vorlesen Druckansicht
Lesezeit: 2 Min.
Von
  • Dr. Harald Bögeholz

Durch Zufall bin ich auf einen Fehler in Java gestoßen, der sowohl unter Windows als auch unter Linux auftritt. Die Anweisung

gibt ‘3304.9999999999995’ aus, das richtige Ergebnis lautet aber offensichtlich 3305. Ähnliche Ungenauigkeiten ergeben sich, wenn ich andere Zahlen mit 100 multipliziere, etwa 33,45, 33,55 und so weiter.[/frage]

[pre]System.out.println(100*33.05);
[/pre]

Das ist kein Fehler in Java, sondern eine Eigenart der Fließkommaarithmetik, die auch bei anderen Programmiersprachen auftritt. Sie rührt daher, dass der Computer intern im Zweiersystem und nur mit einer begrenzten Genauigkeit rechnet. Der Java-Datentyp float hat 32 Bit, von denen 24 auf die Mantisse entfallen, der Typ double ist 64 Bit lang mit 53 Bit Mantisse. Bestimmte Zahlen, die im Dezimalsystem ganz harmlos wirken, weil sie nur endlich viele Nachkommastellen haben, sind im Zweiersystem periodisch und lassen sich daher nicht exakt wiedergeben.

Zunächst zwei einfachere Umrechnungsbeispiele: die Dezimalzahl 5,5 hat die Binärdarstellung 101,1; die Zahl 0,3125 lautet im Zweiersystem 0,0101 (die 1 an der zweiten Stelle nach dem Komma hat die Wertigkeit 1/4, die 1 an der vierten Nachkommastelle 1/16; 1/4 + 1/16 = 0,3125). Diese Zahlen lassen sich in einer float-Variablen exakt darstellen. Die Zahl 0,1 dagegen lautet im Zweiersystem 0,00011001100 ..., eine nicht abbrechende, periodische Zahl. Auch 0,01 ist im Zweiersystem periodisch, ebenso 0,05. Solche Zahlen lassen sich also in einer float- oder double-Variablen prinzipiell nicht exakt speichern, und es kommt zu den von Ihnen beobachteten Ungenauigkeiten. Als Gegenprobe können Sie ja einmal 33,25 · 100 rechnen, das wird Ihr Rechner exakt hinbekommen.

Wer Programme schreibt, die mit Geldbeträgen rechnen, sollte daher unbedingt die Finger von Fließkommavariablen lassen - sonst gibt es beim Addieren von Pfennigbeträgen unangenehme Überraschungen. Viel Ärger kann man sich ersparen, indem man einfach alles in Pfennigen (oder demnächst Euro-Cent) rechnet und in Integer-Variablen speichert. (bo) (bo)