Быстрый обратный квадратный корень

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск
При расчёте освещения OpenArena (свободный порт Quake III: Arena) вычисляет углы падения и отражения через быстрый обратный квадратный корень.

Бы́стрый обра́тный квадра́тный ко́рень (также быстрый InvSqrt() или 0x5f3759df по используемой «магической» константе) — это быстрый приближённый алгоритм вычисления обратного квадратного корня для положительных 32-битных чисел с плавающей запятой. Алгоритм использует целочисленные операции «вычесть» и «битовый сдвиг», а также дробные «вычесть» и «умножить» — без медленных операций «разделить» и «квадратный корень». Несмотря на «хакерство» на битовом уровне, приближение непрерывно: близкие аргументы дают близкий результат. Точности (менее 0,2 % в меньшую сторону и никогда — в большую) не хватает для настоящих численных расчётов, однако вполне достаточно для трёхмерной графики.

Алгоритм[править | править вики-текст]

Алгоритм принимает 32-битное число с плавающей запятой (одинарной точности) в качестве исходных данных, и производит над ним следующие операции:

  • вычисляет половину значения числа и сохраняет для дальнейшего использования
  • трактуя 32-битное с плавающей запятой как 32-битное целое:
  • (в трактовке результата как 32-битного с плавающей запятой на этом этапе получается первое приближение обратного квадратного корня исходного числа)
  • вычисляет одну итерацию метода Ньютона для получения более точного приближения

Алгоритм позволяет вычислять приблизительное значение обратного квадратного корня в среднем в 4 раза быстрее, чем с использованием FPU.

Анализ и погрешность[править | править вики-текст]

Структура 4-байтового дробного такова:

Знак
Порядок Мантисса
0 0 1 1 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
31 24 23 16 15 8 7 0

Имеем дело только с положительными числами (знаковый бит равен нулю), не денормализованными, не и не NaN. Такие числа в стандартном виде записываются как 1,xxxx2·2k[1], и головную единицу не хранят (неявная единица). Кроме того, у машинных дробных чисел смещённый порядок: 20 записывается как 011.1111.12.

Если (а значит, не точная степень двойки), то машинный порядок числа равняется a = 011.1111.12 + k, а порядок числа b = 011.1111.02 − [k/2], [x] — целая часть числа.[2]

Попробуем вывести k через a и b: k = a − 011.1111.12 = 111.1110.02 − 2b. Отсюда b = (1011.1101.12 − a)/2 (при чётном k).

Теперь посмотрим, что будет при нечётном k. В такой ситуации b на единицу больший, и оба случая можно объединить в формулу: b = [(1011.1110.02a)/2].

Если добавить справа биты мантиссы (обозначенные звёздочками), то конструкции b*** = [(1011.1110.0***0 − a***)/2] и b*** = (101.1111.00*** − [a***/2]) отличаются одним младшим битом мантиссы. Что и даёт: верхний байт 5F, второй в диапазоне 00…3F. Оставшиеся биты мантиссы подбираются так, чтобы минимизировать погрешность.

Оценим магическую константу. Поскольку при мантисса результата не изменится, достаточно рассмотреть два диапазона: [1, 2) и [2, 4). Легко видеть, что на самом деле сдвиг-вычитание — грубая кусочно-линейная аппроксимация:

  • Для явная часть мантиссы x равняется , мантисса результата начинается с 1,12 = 1,5 (неявная единица, двоичная запятая, затем единица, пришедшая из порядка), порядок 011.1111.02 ≡ 2−1 = 0,5, и (c — мантисса магической константы; по вышеприведённым расчётам ).
  • Для  — явная часть мантиссы x равняется , мантисса результата начинается с 1,02 = 1, порядок тот же, и .
  • Когда вычисленное на предыдущем этапе окажется меньше 0,5, происходит заём из поля порядка, и .

Легко видеть, что . очевидно «сшивается» с . Совпадающий с результат получается, если расписать формулы для . Потому наша кусочно-линейная аппроксимация непрерывна.

Наши расчёты грубые и прикидочные, так что обойдёмся условием: минимизировать относительную погрешность на концах первого отрезка, без учёта метода Ньютона. Поскольку , и линейная функция на отрезке падает на 0,25, то . Таким образом, магическая константа — дробное число с порядком ровно 101.1111.02 ≡ 263 и мантиссой приблизительно 1,45.

Метод Ньютона даёт , , и . Поскольку функция убывает и выпукла вниз, итерация метода Ньютона даёт лучшую точность, если начальное приближение будет меньше реального. Так что реальная константа должна быть меньше наших расчётных 1,45. После одного шага метода Ньютона результат получается довольно точный (+0 % −0,17 %), что для целей компьютерной графики вполне подходит. Такая погрешность сохраняется почти на всём диапазоне нормированных дробных чисел.

Неизвестно, откуда взялась константа 0x5f3759df ≈ 1,432430·263. Перебором Крис Ломонт и Мэттью Робертсон выяснили, что наилучшая константа для float — 0x5f375a86 ≈ 1,432450·263, для double — 0x5fe6eb50c7b537a9. Правда, для double алгоритм бессмысленный (не даёт выигрыша в точности по сравнению с float). Более тонкие расчёты, учитывающие метод Ньютона, дают результат, совпадающий с эмпирической константой Ломонта[3].

Существуют аналогичные алгоритмы для других степеней, например, квадратного или кубического корня[4].

Реализация из Quake III: Arena[править | править вики-текст]

float Q_rsqrt( float number )
{
	long i;
	float x2, y;
	const float threehalfs = 1.5F;

	x2 = number * 0.5F;
	y  = number;
	i  = * ( long * ) &y;                       // evil floating point bit level hacking
	i  = 0x5f3759df - ( i >> 1 );               // what the fuck? 
	y  = * ( float * ) &i;
	y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
//	y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

	return y;
}

История[править | править вики-текст]

Алгоритм был, вероятно, разработан в Silicon Graphics в 1990-х, а реализация появилась в 1999 году в исходном коде компьютерной игры Quake III Arena, но данный метод не появлялся на общедоступных форумах, таких как Usenet, до 2002—2003-х годов. Алгоритм генерирует достаточно точные результаты, используя уникальное первое приближение метода Ньютона. В то время основным преимуществом алгоритма был отказ от дорогих вычислительных операций с плавающей запятой в пользу целочисленных операций. Обратные квадратные корни используются для расчета углов падения и отражения для освещения и затенения в компьютерной графике.

Алгоритм изначально приписывался Джону Кармаку, но тот признался, что его в id Software принёс Майкл Абраш. Изучение вопроса показало, что код имел более глубокие корни как в аппаратной, так и в программной сферах компьютерной графики. Исправления и изменения производились как Silicon Graphics, так и 3dfx Interactive, при этом как самое раннее использование известна реализация Гэри Таролли для SGI Indigo.

С выходом в свет в 1998 году набора инструкций 3DNow! в процессорах фирмы AMD появилась ассемблерная инструкция PFRSQRT для быстрого приближенного вычисления инверсного квадратного корня. Также можно получить константу для чисел двойной точности, но это бессмысленно, так как точность вычислений не увеличится, поэтому инструкции для вычисления быстрого обратного квадратного корня для чисел двойной точности не была добавлена.

Мотивация[править | править вики-текст]

Поверхность нормалей широко используются в расчетах освещения и затенения, требующих расчета норм для векторов. Здесь показано поле векторов нормали к поверхности.

Инверсный квадратный корень числа с плавающей запятой используется для вычисления нормализованного вектора. Так как программа с 3D-графикой использует эти нормализованные векторы для определения освещения и отражения, за секунду должны вычисляться миллионы этих корней. До того как было создано специальное аппаратное обеспечение для обработки трансформаций и освещения, программное обеспечение вычислений могло быть медленным. В частности, в начале 1990-х, когда код был разработан, большинство вычислений с плавающей запятой отставало по производительности от операций с целыми числами.

Чтобы нормализовать вектор, надо сначала определить его длину путём вычисления его нормы: квадратный корень суммы квадратов компонент вектора, а затем каждый компонент вектора разделить на полученную длину. Получается новый вектор, называемый единичным, и направленный в том же направлении, что и исходный.

 — это евклидова норма вектора, аналог Евклидова расстояния между двумя точками в пространстве.
 — это нормализованный единичный вектор. Вычисленное обозначим как ,
, определяет соотношение единичного вектора и обратного квадратного корня от .

Quake III Arena использует алгоритм быстрого обратного квадратного корня для ускорения обработки графики вычислительными блоками, но с тех пор алгоритм уже был реализован в некоторых специализированных аппаратных вершинных шейдерах, используя специальные программируемые матрицы (FPGA).

Примечания[править | править вики-текст]

  1. Распространена запись машинного дробного и как 1,xxxx2·2k, и 0,1xxxx2·2k+1. Мы будем придерживаться первого варианта.
  2. В двоичных числах точки стоят по границам полубайтов — в часности, порядок числа состоит из 7 битов верхнего байта и одного бита второго байта.
  3. http://irbis-nbuv.gov.ua/cgi-bin/irbis_nbuv/cgiirbis_64.exe?C21COM=2&I21DBN=UJRN&P21DBN=UJRN&IMAGE_FILE_DOWNLOAD=1&Image_file_name=PDF/Ktd_2014_32_6.pdf
  4. http://h14s.p5r.org/2012/09/0x5f3759df.html

Ссылки[править | править вики-текст]