Грег Хьюгилл и 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 перейдет, но остановится раньше, таким образом набирает скорость расчета.