Greg Hewgill und IllidanS4 gaben einen Link mit ausgezeichneter mathematischer Erklärung. Ich werde versuchen, es hier für diejenigen zusammenzufassen, die nicht zu sehr ins Detail gehen wollen.
Jede mathematische Funktion kann mit einigen Ausnahmen durch eine Polynomsumme dargestellt werden:
y = f(x)
kann genau umgewandelt werden in:
y = a0 + a1*x + a2*(x^2) + a3*(x^3) + a4*(x^4) + ...
Wobei a0, a1, a2, ... Konstanten sind . Das Problem ist, dass für viele Funktionen, wie die Quadratwurzel, diese Summe für den exakten Wert unendlich viele Mitglieder hat und nicht bei x ^ n endet . Aber wenn wir bei x ^ n anhalten haben wir immer noch ein Ergebnis mit einer gewissen Präzision.
Also, wenn wir haben:
y = 1/sqrt(x)
In diesem speziellen Fall haben sie beschlossen, alle Polynomelemente über der Sekunde zu verwerfen, wahrscheinlich aufgrund der Berechnungsgeschwindigkeit:
y = a0 + a1*x + [...discarded...]
Und jetzt ist die Aufgabe gekommen, a0 und a1 zu berechnen, damit y den geringsten Unterschied zum exakten Wert aufweist. Sie haben berechnet, dass die am besten geeigneten Werte sind:
a0 = 0x5f375a86
a1 = -0.5
Wenn Sie dies in eine Gleichung setzen, erhalten Sie:
y = 0x5f375a86 - 0.5*x
Welches ist das gleiche wie die Zeile, die Sie im Code sehen:
i = 0x5f375a86 - (i >> 1);
Edit: eigentlich ist hier y = 0x5f375a86 - 0.5*x
nicht das gleiche wiei = 0x5f375a86 - (i >> 1);
seit dem Verschieben von Float als Ganzzahl nicht nur durch zwei geteilt, sondern auch Exponent durch zwei geteilt und einige andere Artefakte verursacht, aber es kommt immer noch darauf an, einige Koeffizienten a0, a1, a2 ... zu berechnen.
Zu diesem Zeitpunkt haben sie herausgefunden, dass die Genauigkeit dieses Ergebnisses für diesen Zweck nicht ausreicht. Daher haben sie zusätzlich nur einen Schritt der Newtonschen Iteration durchgeführt, um die Ergebnisgenauigkeit zu verbessern:
x = x * (1.5f - xhalf * x * x)
Sie hätten einige weitere Iterationen in einer Schleife durchführen können, wobei jede das Ergebnis verbessert, bis die erforderliche Genauigkeit erreicht ist. Genau so funktioniert es in CPU / FPU! Aber es scheint, dass nur eine Iteration ausreichte, was auch ein Segen für die Geschwindigkeit war. Die CPU / FPU führt so viele Iterationen wie nötig durch, um die Genauigkeit für die Gleitkommazahl zu erreichen, in der das Ergebnis gespeichert ist, und verfügt über einen allgemeineren Algorithmus, der in allen Fällen funktioniert.
Kurz gesagt, was sie getan haben, ist:
Verwenden Sie (fast) den gleichen Algorithmus wie CPU / FPU, nutzen Sie die Verbesserung der Anfangsbedingungen für den Sonderfall 1 / sqrt (x) und berechnen Sie nicht bis zur Präzision, zu der CPU / FPU gehen, sondern früher aufhören Berechnungsgeschwindigkeit gewinnen.