Greg Hewgill i IllidanS4 podał link z doskonałym wyjaśnieniem matematycznym. Spróbuję to podsumować tutaj dla tych, którzy nie chcą zbytnio zagłębiać się w szczegóły.
Każda funkcja matematyczna, z pewnymi wyjątkami, mogą być reprezentowane przez sumę wielomianu:
y = f(x)
może być dokładnie przekształcony:
y = a0 + a1*x + a2*(x^2) + a3*(x^3) + a4*(x^4) + ...
Gdzie A0, A1, A2 ,. .. są stałych. Problem polega na tym, że dla wielu funkcji, takich jak pierwiastek kwadratowy, dla dokładnej wartości ta suma ma nieskończoną liczbę członków, to nie kończy się na jakiejś x^n. Ale jeśli zatrzymamy się na jakimś x^n nadal będziemy mieli wynik do pewnej precyzji.
Tak więc, jeśli mamy:
y = 1/sqrt(x)
W tym konkretnym przypadku postanowili odrzucić wszystkie wielomianowych członków powyższe sekundę, prawdopodobnie ze względu na szybkość obliczeń:
y = a0 + a1*x + [...discarded...]
a zadanie ma teraz przyszedł w dół, aby obliczyć a0 i a1, aby y miały najmniejszą różnicę w stosunku do dokładnej wartości. Oni obliczyli, że najbardziej odpowiednie są następujące wartości:
a0 = 0x5f375a86
a1 = -0.5
Więc kiedy można umieścić to w równaniu otrzymasz:
y = 0x5f375a86 - 0.5*x
który jest taki sam jak w wierszu widać w kodzie:
i = 0x5f375a86 - (i >> 1);
Edytuj: faktycznie tutaj y = 0x5f375a86 - 0.5*x
to nie to samo, co i = 0x5f375a86 - (i >> 1);
, ponieważ zmiana liczby zmiennoprzecinkowej jako liczby całkowitej nie tylko dzieli się przez dwa, ale również dzieli wykładnik o dwie 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 wystarcza do tego celu. Więc dodatkowo zrobił tylko jeden krok iteracji Newtona do poprawy dokładności wyników:
x = x * (1.5f - xhalf * x * x)
Mogli zrobić trochę więcej iteracji w pętli, każdy poprawiając wynik, aż wymagana dokładność jest spełniony. Dokładnie 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 prędkości. CPU/FPU wykonuje tyle iteracji, ile potrzeba, aby osiągnąć dokładność liczby zmiennoprzecinkowej, w której zapisany jest wynik, i ma bardziej ogólny algorytm, który działa we wszystkich przypadkach.
Tak w skrócie, to co zrobili to:
Zastosowanie (prawie) taki sam algorytm jak CPU/FPU, wykorzystać poprawę warunków początkowych dla szczególnego przypadku 1/sqrt (x) i nie obliczaj całej drogi do precyzji CPU/FPU, ale zatrzymaj się wcześniej, zyskując w ten sposób prędkość obliczeń.
To zostało napisane o milionach razy. Zobacz: http://www.google.com/search?q=0x5f3759df –
Dzięki, ale. Było to o wiele bardziej interesujące pytanie niż "jak zrobić liczbę dodatnią ujemną w C#?" – MusiGenesis
Nie był Carmack. http://en.wikipedia.org/wiki/Fast_inverse_square_root – h4xxr