Da 0.1
nicht 0,1; dieser Wert nicht in doppelter Genauigkeit darstellbare, es wird auf die nächste Zahl mit doppelter Genauigkeit, die genau so gerundet:
0.1000000000000000055511151231257827021181583404541015625
Wenn Sie fmod
nennen, erhalten Sie den Rest der Division durch den Wert oben aufgeführten, das ist genau das:
0.0999999999999999500399638918679556809365749359130859375
, die 0.1
runden (oder vielleicht 0.09999999999999995
), wenn Sie es drucken.
Mit anderen Worten, funktioniert fmod
perfekt, aber Sie geben es nicht die Eingabe, die Sie denken, Sie sind.
Edit: Ihre eigene Implementierung gibt Ihnen die richtige Antwort, weil es ungenaue, es glaubt oder nicht. Zunächst einmal, beachte, dass fmod
den Rest ohne Rundungsfehler berechnet; Die einzige Ungenauigkeitsquelle ist der Darstellungsfehler, der durch Verwendung des Werts 0.1
eingeführt wurde. Sehen wir uns nun Ihre Implementierung an und sehen Sie, wie der Rundungsfehler, den sie verursacht, den Darstellungsfehler genau aufhebt.
Evaluieren a - floor(a/n) * n
ein Schritt zu einem Zeitpunkt, an jeder Stufe berechnet die genauen Werte zu verfolgen:
Zuerst wir 1.0/n
bewerten, wo n
zu 0.1
die Nähe doppelter Genauigkeit Näherung ist wie oben gezeigt. Das Ergebnis dieser Division ist ungefähr:
9.999999999999999444888487687421760603063276150363492645647081359...
Beachten Sie, dass dieser Wert nicht darstellbare Zahl mit doppelter Genauigkeit ist - so wird es abgerundet.Um zu sehen, wie diese Rundung geschieht, schauen wir uns die Zahl in binärer aussehen statt dezimal:
1001.1111111111111111111111111111111111111111111111111 10110000000...
Der Raum zeigt an, wo die Rundung mit doppelter Genauigkeit erfolgt. Da der Teil nach dem runden Punkt größer ist als der exakte halbe Punkt, wird dieser Wert auf genau 10
gerundet.
floor(10.0)
ist, vorhersagbar, 10.0
. Alles, was übrig bleibt, ist 1.0 - 10.0*0.1
zu berechnen.
im Binär-, der genaue Wert von 10.0 * 0.1
ist:
1.0000000000000000000000000000000000000000000000000000 0100
wieder, dieser Wert nicht darstellbaren als Doppel, und so wird an der Position durch einen Raum angegeben gerundet. Diesmal rundet es auf genau 1.0
, und so ist die endgültige Berechnung 1.0 - 1.0
, die natürlich 0.0
ist.
Ihre Implementierung enthält zwei Rundungsfehler, die in diesem Fall den Darstellungsfehler des Wertes 0.1
exakt aufheben. fmod
dagegen ist immer genau (zumindest auf Plattformen mit einer guten Numerikbibliothek) und macht den Darstellungsfehler von 0.1
.
gibt hier 0.09999999999999995 zurück (OS X, Python 2.5.4). Die Antwort hängt von der C-Bibliothek Ihrer Plattform ab. – geoffspear
ok, tut mir leid, ich habe die Rundung gemacht. Wie auch immer, die Antwort sollte 0 in meinem Verständnis sein, seit 1.0/0.1 = 10, was eine ganze Zahl ist. – beemtee