(Hinweis: Ich werde 'b' anhängen, um hier Binärzahlen anzugeben. Alle anderen Zahlen werden dezimal angegeben.)
Eine Möglichkeit, über Dinge nachzudenken, ist die wissenschaftliche Notation. Wir sind es gewohnt, Zahlen in wissenschaftlicher Notation wie 6.022141 * 10 ^ 23 zu sehen. Gleitkommazahlen werden intern in einem ähnlichen Format gespeichert - Mantisse und Exponent, jedoch mit Zweierpotenzen anstelle von zehn.
Ihre 61.0 könnte mit der Mantisse und den Exponenten als 1.90625 * 2 ^ 5 oder 1.11101b * 2 ^ 101b umgeschrieben werden. Um dies mit zehn zu multiplizieren und (den Dezimalpunkt zu verschieben), können wir Folgendes tun:
(1,90625 * 2 ^ 5) * (1,25 * 2 ^ 3) = (2,3828125 * 2 ^ 8) = (1,19140625 * 2 ^ 9)
oder in mit der Mantisse und Exponenten in binär:
(1.11101b * 2 ^ 101b) * (1.01b * 2 ^ 11b) = (10.0110001b * 2 ^ 1000b) = (1.00110001b * 2 ^ 1001b)
Beachten Sie, was wir dort getan haben, um die Zahlen zu multiplizieren. Wir haben die Mantissen multipliziert und die Exponenten hinzugefügt. Da die Mantisse größer als zwei endete, normalisierten wir das Ergebnis durch Anstoßen des Exponenten. Es ist genau so, als würden wir den Exponenten anpassen, nachdem wir eine Operation mit Zahlen in dezimaler wissenschaftlicher Notation durchgeführt haben. In jedem Fall hatten die Werte, mit denen wir gearbeitet haben, eine endliche Darstellung in Binärform, und so erzeugten die Werte, die durch die grundlegenden Multiplikations- und Additionsoperationen ausgegeben wurden, auch Werte mit einer endlichen Darstellung.
Überlegen Sie nun, wie wir 61 durch 10 teilen würden. Wir beginnen mit der Teilung der Mantissen 1.90625 und 1.25. In Dezimalzahlen ergibt dies 1,525, eine schöne kurze Zahl. Aber was ist das, wenn wir es in eine Binärdatei konvertieren? Wir machen das auf die übliche Weise - subtrahieren die größte Zweierpotenz, wann immer dies möglich ist, genau wie das Konvertieren von ganzzahligen Dezimalstellen in Binärzahlen, aber wir verwenden negative Zweierpotenzen:
1,525 - 1 * 2 ^ 0 -> 1
0,525 - 1 * 2 ^ -1 -> 1
0,025 - 0 * 2 ^ -2 -> 0
0,025 - 0 * 2 ^ -3 -> 0
0,025 - 0 * 2 ^ -4 -> 0
0,025 - 0 * 2 ^ -5 -> 0
0,025 - 1 * 2 ^ -6 -> 1
0,009375 - 1 * 2 ^ -7 -> 1
0,0015625 - 0 * 2 ^ -8 -> 0
0,0015625 - 0 * 2 ^ -9 -> 0
0,0015625 - 1 * 2 ^ -10 -> 1
0,0005859375 - 1 * 2 ^ -11 -> 1
0,00009765625 ...
Oh oh. Jetzt sind wir in Schwierigkeiten. Es stellt sich heraus, dass 1,90625 / 1,25 = 1,525 ein sich wiederholender Bruch ist, wenn er in Binärform ausgedrückt wird: 1,11101b / 1,01b = 1,10000110011 ... b Unsere Maschinen haben nur so viele Bits, um diese Mantisse zu halten, und runden den Bruch nur ab und nehme Nullen über einen bestimmten Punkt hinaus an. Der Fehler, den Sie sehen, wenn Sie 61 durch 10 teilen, ist der Unterschied zwischen:
1.100001100110011001100110011001100110011 ... b * 2 ^ 10b
und sagen wir:
1.100001100110011001100110b * 2 ^ 10b
Es ist diese Rundung der Mantisse, die zu einem Genauigkeitsverlust führt, den wir mit Gleitkommawerten assoziieren. Selbst wenn die Mantisse genau ausgedrückt werden kann (z. B. wenn nur zwei Zahlen addiert werden), können wir dennoch einen numerischen Verlust erhalten, wenn die Mantisse nach dem Normalisieren des Exponenten zu viele Ziffern benötigt, um zu passen.
Wir machen so etwas tatsächlich die ganze Zeit, wenn wir Dezimalzahlen auf eine überschaubare Größe runden und nur die ersten paar Ziffern davon angeben. Da wir das Ergebnis dezimal ausdrücken, fühlt es sich natürlich an. Wenn wir jedoch eine Dezimalstelle runden und sie dann in eine andere Basis konvertieren, sieht sie genauso hässlich aus wie die Dezimalstellen, die wir aufgrund der Gleitkomma-Rundung erhalten.