Greg Hewgill y IllidanS4 hat einen Link mit einer ausgezeichneten mathematischen Erklärung angegeben. Ich werde versuchen, es hier für diejenigen zusammenzufassen, die nicht zu sehr ins Detail gehen wollen.
Jede mathematische Funktion, mit einigen Ausnahmen, kann durch eine Polynomsumme dargestellt werden:
y = f(x)
kann sein genau in umgewandelt:
y = a0 + a1*x + a2*(x^2) + a3*(x^3) + a4*(x^4) + ...
Dabei sind a0, a1, a2,... Konstanten . Das Problem ist, dass für viele Funktionen, wie z. B. Quadratwurzel, für den exakten Wert diese Summe eine unendliche Anzahl von Gliedern hat, sie endet nicht bei einem x^n . Aber, wenn wir bei einigen x^n hätten wir immer noch ein Ergebnis bis zu einer gewissen Genauigkeit.
Also, wenn wir haben:
y = 1/sqrt(x)
In diesem speziellen Fall haben sie beschlossen, alle Polynomglieder über der zweiten zu verwerfen, wahrscheinlich aus Gründen der Rechengeschwindigkeit:
y = a0 + a1*x + [...discarded...]
Die Aufgabe besteht nun darin, a0 und a1 so zu berechnen, dass y die geringste Abweichung vom exakten Wert aufweist. Sie haben berechnet, dass die am besten geeigneten Werte sind:
a0 = 0x5f375a86
a1 = -0.5
Wenn man dies in die Gleichung einbezieht, erhält man also:
y = 0x5f375a86 - 0.5*x
Das ist die gleiche Zeile wie die im Code:
i = 0x5f375a86 - (i >> 1);
Edit: eigentlich hier y = 0x5f375a86 - 0.5*x
ist nicht dasselbe wie i = 0x5f375a86 - (i >> 1);
da das Verschieben von Float als Integer nicht nur durch zwei dividiert, sondern auch den Exponenten durch zwei teilt und einige andere Artefakte verursacht, aber es geht immer noch um die Berechnung einiger Koeffizienten a0, a1, a2... .
Zu diesem Zeitpunkt haben sie festgestellt, dass die Genauigkeit dieses Ergebnisses nicht ausreicht. Daher wurde zusätzlich nur ein Schritt der Newtonschen Iteration durchgeführt, um die Genauigkeit des Ergebnisses zu verbessern:
x = x * (1.5f - xhalf * x * x)
Sie hätten einige weitere Iterationen in einer Schleife durchführen können, wobei jede einzelne das Ergebnis verbessert hätte, bis die erforderliche Genauigkeit erreicht ist. Genau so funktioniert es in CPU/FPU! Aber es scheint, dass nur eine Iteration ausreichend war, was auch ein Segen für die Geschwindigkeit war. Die CPU/FPU führt so viele Iterationen durch, wie erforderlich sind, um die Genauigkeit der Fließkommazahl zu erreichen, in der das Ergebnis gespeichert wird, und sie verfügt über einen allgemeineren Algorithmus, der für alle Fälle geeignet ist.
Kurz gesagt, was sie getan haben, ist:
Verwenden Sie (fast) denselben Algorithmus wie CPU/FPU, nutzen Sie die Verbesserung der Anfangsbedingungen für den Sonderfall 1/sqrt(x) und rechnen Sie nicht bis zur Genauigkeit, die CPU/FPU erreicht, sondern brechen Sie früher ab, wodurch Sie an Rechengeschwindigkeit gewinnen.