Greg Hewgill i IllidanS4 podali link z doskonałym wyjaśnieniem matematycznym. Spróbuję podsumować to tutaj dla tych, którzy nie chcą wdawać się w szczegóły.
Dowolną funkcję matematyczną, z pewnymi wyjątkami, można przedstawić za pomocą sumy wielomianów:
y = f(x)
można dokładnie przekształcić w:
y = a0 + a1*x + a2*(x^2) + a3*(x^3) + a4*(x^4) + ...
Gdzie a0, a1, a2, ... są stałymi . Problem polega na tym, że dla wielu funkcji, takich jak pierwiastek kwadratowy, dla dokładnej wartości suma ta ma nieskończoną liczbę elementów, nie kończy się na jakimś x ^ n . Ale jeśli zatrzymamy się na jakimś x ^ n , nadal otrzymamy wynik z pewną precyzją.
Więc jeśli mamy:
y = 1/sqrt(x)
W tym konkretnym przypadku postanowili odrzucić wszystkie składowe wielomianu powyżej sekundy, prawdopodobnie z powodu szybkości obliczeń:
y = a0 + a1*x + [...discarded...]
Zadanie sprowadza się teraz do obliczenia a0 i a1, aby y miało najmniejszą różnicę od dokładnej wartości. Obliczyli, że najbardziej odpowiednie wartości to:
a0 = 0x5f375a86
a1 = -0.5
Więc kiedy umieścisz to w równaniu, otrzymasz:
y = 0x5f375a86 - 0.5*x
Która jest taka sama jak linia, którą widzisz w kodzie:
i = 0x5f375a86 - (i >> 1);
Edycja: właściwie y = 0x5f375a86 - 0.5*x
to nie to samo, co i = 0x5f375a86 - (i >> 1);
od czasu, gdy przesunięcie liczby zmiennoprzecinkowej jako liczby całkowitej nie tylko dzieli przez dwa, ale również dzieli wykładnik przez dwa i powoduje inne artefakty, ale nadal sprowadza się do obliczenia niektórych współczynników a0, a1, a2 ....
W tym momencie odkryli, że precyzja tego wyniku nie jest wystarczająca do tego celu. Więc dodatkowo wykonali tylko jeden krok iteracji Newtona, aby poprawić dokładność wyników:
x = x * (1.5f - xhalf * x * x)
Mogli wykonać więcej iteracji w pętli, z których każda poprawiała wynik, aż do osiągnięcia wymaganej dokładności. Dokładnie tak to działa w CPU / FPU! Ale wydaje się, że wystarczyła tylko jedna iteracja, co było również błogosławieństwem dla szybkości. CPU / FPU wykonuje tyle iteracji, ile potrzeba, aby osiągnąć dokładność liczby zmiennoprzecinkowej, w której przechowywany jest wynik, i ma bardziej ogólny algorytm, który działa we wszystkich przypadkach.
Krótko mówiąc, zrobili:
Użyj (prawie) tego samego algorytmu, co CPU / FPU, wykorzystaj poprawę warunków początkowych dla specjalnego przypadku 1 / sqrt (x) i nie obliczaj aż do osiągnięcia precyzji CPU / FPU, ale zatrzymaj się wcześniej, w ten sposób przyspieszenie obliczeń.