Das Problem ist der float an sich.
Warum?
Ein float wird mit 4 Byte implementiert. Das
bedeutet, dass du in etwa mit 6 signifikanten Stellen
rechnen kannst. Bei einer Zahl 1013.25 hast du bereits
4 Stellen für den Vorkommaanteil verbraucht, die beiden
restlichen Stellen gehen für die beiden nachkommastellen
drauf.
Nur: Dann darfst du nicht mit der Zahl rechnen. In dem
Momement, in dem du etwas Arithmetik betreibst schrumpfen
die 6 Stellen ganz schnell zu 5 Stellen und bei weiteren
Berechnungen noch sehr viel schneller zu 4 Stellen. Von
den ursprünglichen 6 signifikanten Stellen sind nur noch
4 übrig geblieben, alles andere danch ist nur noch gelogen (*)
Nun hast du aber eine Menge Berechnungen. Selbst wenn du
ursprünglich mit der Zahl 1013.1 gestartet wärest, würde da
nach dem Abziehen der ganzzahligen Anteile keine 0.1 heraus-
kommen. Durch die ganzen Zwischenberechnungen hast du sukzessive
immer mehr Genauigkeit verloren.
Ein etwas vertrauteres Beispiel:
Du kennst doch periodische Zahlen. Ein Beispiel: 1/3
Angenommen ich lasse dir 6 signifikante Ziffern zu.
Wenn du dann 1/3 berechnen sollst, dann kommt da 0.333333
heraus. Aber so sehr du dich auch windest, 0.333333 * 3
wird nicht mehr 1.0 ergeben. Des Ergebnis 0.999999 ist zwar
sehr nahe an 1.0 aber eben nicht exakt 1.0
Wenn ich da jeztt weiter rechne, zb 3 addieren
0.999999 + 3.0 -> 2.99999
(warum nur 5 Nachkommastellen? Zähle die signifikanten Stellen,
es sind immer noch 6, aber für die eine jetzt signifikante
Vorkommastelle fällt eine Nachkommastelle weg).
und das wiederrum durch 3 dividieren
2.99999 / 3
dann kommt als Ergebnis 0.999996 heraus.
Rein Mathematisch müsste das Ergebnis immer noch 1.0 sein, aber
Floating Point Berechnungen haben nun mal mit Mathematik sehr
wenig zu tun.
Man sieht aber auch, wie sich der Fehler, je nach tatsächlichen
Zahlen und Operationen vergrößert.
Soweit zum Dezimalsystem. Im Binärsystem, in dem deine Floating
Point Operationen ablaufen ist das im Prinzip nicht anders. Eher
sogar schlimmer, weil es dort sehr viel mehr periodische Zahlen
gibt. Z.b. ist 0.1, also 1/10, in diesem Zahlensystem nicht
exakt darstellbar, da es eine periodische Zahl ist.
Konklusio:
Vermeide float wenn immer du kannst. Wenns gar nicht anders geht,
dann nimm sie, aber achte sehr genau darauf welche Operationen
du in welcher Reichenfolge machst und welche Zahlen da beteilgt
sind. Leider gibt es da kein Patentrezept, sondern jeder einzelne
Fall muss seperat für sich untersucht werden. Und solche Untersuchungen
können einen in den Wahnsinn treiben.
Rechnen mit Gleitkommazahlen
ist wie das Umschaufeln eines Sandhaufens.
Je öfter man es macht,
desto mehr Sand verliert man und
desto mehr Dreck mischt man in den Sand.
(*) gelogen ist ein hartes Wort. Natürlich kann man erklären
wie die weiteren Nachkommastellen zustande kommen, aber da
muss man schon sehr tief in Fliesskommaverarbeitung einsteigen.