Fehler in der Funktion »Obergrenze«
Wenn ich in RagTime die Obergrenze von 2,7/0,15 ausrechne, kommt 19 heraus. Es muss aber 18 sein. Weshalb rechnet RagTime hier falsch? (Die Formel im Rechenblatt: »Obergrenze(2,7/0,15)«)
Leider ist die Antwort sehr technisch.
Dies ist in eines der vertrackten Probleme von numerischem Rechnen auf Computern. Leider ist dieses Problem wenig bekannt. Die Annahme ist immer: »Rechnen können Computer schon richtig«. Leider können sie es bei Zahlen mit Nachkommastellen oft gar nicht! Das Problem ist nicht prinzipiell lösbar. ich versuche das mal am Beispiel »Obergrenze(2,7/0,15)« zu erklären. Die Formel liefert 19, »2,7/0,15« dagegen 18.
Nur zum Spaß hab ich dasselbe mal in AppleScript und PHP probiert. AppleScript: »round (2.7 / 0.15) rounding up« liefert 19, »2.7 / 0.15« dagegen 18.0. PHP: »ceil(2.7 / 0.15))« liefert 19, »2.7 / 0.15« liefert 18. Dies nur als Illustration, dass RagTime da in guter Gesellschaft ist.
Was da passiert:
Zuerst ein Beispiel im Dezimalsystem. 1/3 ergibt 0,3333333333… Die Zahl ist periodisch. Rechnet man mit begrenzt viele Stellen, wird irgendwo abgeschnitten. Die Zahl ist dann nicht mehr genau. Nehmen wir als Beispiel 5 Nachkommastellen. »(1/3)*3« mit fünf Nachkommastellen gerechnet ergibt 0,99999 und nicht 1.
Sehr viele Zahlen, die im Dezimalsystem ganz einfach aussehen (0,1 zum Beispiel), sind dual periodisch. Das bedeutet: Der Rechner kann sie intern nicht exakt darstellen. Man kann auch sagen: Die Zahl 0,1 gibt es auf einem Rechner schlicht nicht. Es gibt nur einen Wert dicht dran.
Bei einer Zahl mit 64 bit (wohl am häufigsten benutzt) wird 2,7 im Hauptspeicher zu 2,7000000000000002. Aus der Zahl 0,15 wird intern 0,14999999999999999. Und mit den Zahlen wird dann gerechnet. Das Ergebnis von »2,7 / 0,15« ist intern im Rechner »18.000000000000004«. Das dürfte das Ergebnis auf jedem Rechner sein, der ISO-konform mit einer 64-bit-Zahl rechnet.
Rechenblätter kaschieren das Problem bisweilen, und dann auch durch runden. In AppleScript liefert «(0.1 + 0.1 + 0.1 - 0.3) = 0» das Ergebnis »false« (der entsprechende Ausdruck in PHP, »(0.1 + 0.1 + 0.1 - 0.3) == 0«, ebenfalls). In RagTime liefert der entsprechende Ausdruck im Rechenblatt 1 (also true oder wahr). Intern sind die Ausdrücke tatsächlich nicht gleich. Der Klammerausdruck liefert «5,5511151231257827 * 1017». Das korrekte Ergebnis in RagTime entsteht nur, weil wir dort absichtlich ungenauer rechnen (d.h. runden). Diese Tricks werden aber immer nur einen Teil der Fälle abfangen. (Verschiedene Tabellenkalkulationsprogramme verwenden leicht unterschiedliche Tricks, deshalb sind die Beispiele, in denen so ein Problem offensichtlich wird, auch verschieden.)
Wenn man die maximale Anzahl der möglichen Nachkommastellen kennt, kann man sich mit Runden helfen: »Obergrenze(Runden(2,7/0,15;5)
Dieser Text ist sehr technisch, aber es handelt sich wirklich um ein Grundsatzproblem des numerischen Rechnens mit Fließkommazahlen auf Computern. Eigentlich sind diese Zahlen mit dem Konzept exakter Schwellwerte (wie sie beim Auf- und Abrunden nun einmal vorkommen) nicht verträglich. Bei Zahlen mit Nachkommastellen kann man sich auf bestimmte Berechnungen am Computer nicht verlassen!