Грег Х'югілл і IllidanS4 дали посилання з відмінним математичним поясненням. Я спробую підсумувати це для тих, хто не хоче надто детально вникати.
Будь-яка математична функція, за деякими винятками, може бути представлена багаточленною сумою:
y = f(x)
можна точно перетворити на:
y = a0 + a1*x + a2*(x^2) + a3*(x^3) + a4*(x^4) + ...
Де a0, a1, a2, ... - константи . Проблема полягає в тому, що для багатьох функцій, таких як квадратний корінь, для точного значення ця сума має нескінченну кількість членів, вона не закінчується на деякому x ^ n . Але, якщо ми зупинимось на деякому x ^ n, ми все одно матимемо результат до деякої точності.
Отже, якщо ми маємо:
y = 1/sqrt(x)
У цьому конкретному випадку вони вирішили відкинути всі члени полінома вище секунди, можливо, через швидкість обчислення:
y = a0 + a1*x + [...discarded...]
І тепер завдання зійшло обчислити a0 і a1, щоб y мав найменшу різницю від точного значення. Вони підрахували, що найбільш підходящі значення:
a0 = 0x5f375a86
a1 = -0.5
Отже, коли ви покладете це в рівняння, ви отримаєте:
y = 0x5f375a86 - 0.5*x
Що таке саме рядок, який ви бачите в коді:
i = 0x5f375a86 - (i >> 1);
Редагувати: насправді тут y = 0x5f375a86 - 0.5*x
не те саме, що, i = 0x5f375a86 - (i >> 1);
оскільки зсув плавця як ціле число не тільки ділиться на два, але й ділить експонент на два і викликає деякі інші артефакти, але все ж зводиться до обчислення деяких коефіцієнтів a0, a1, a2 ....
У цей момент вони з'ясували, що точності цього результату недостатньо для досягнення мети. Таким чином, вони також зробили лише один крок ітерації Ньютона для підвищення точності результату:
x = x * (1.5f - xhalf * x * x)
Вони могли зробити ще кілька ітерацій у циклі, кожен з яких покращує результат, поки не буде досягнуто необхідної точності. Саме так воно працює в CPU / FPU! Але, здається, було достатньо лише однієї ітерації, що також було благом для швидкості. CPU / FPU робить стільки ітерацій, скільки потрібно для досягнення точності для числа з плаваючою комою, в якому зберігається результат, і він має більш загальний алгоритм, який працює для всіх випадків.
Отже, коротше, що вони зробили:
Використовуйте (майже) той же алгоритм, що і CPU / FPU, використовуйте поліпшення початкових умов для особливого випадку 1 / sqrt (x) і не обчислюйте весь шлях до точності CPU / FPU піде, але зупиниться раніше, таким чином набираючи швидкість обчислення.