Когда вы используете Ньютона-Рафсона для вычисления квадратного корня, вы на самом деле хотите использовать итерацию, чтобы найти обратный квадратный корень (после чего вы можете просто умножить на вход - с некоторой тщательностью для округления - для полученияквадратный корень).
Точнее: мы используем функцию f(x) = x^-2 - n
.Понятно, что если f(x) = 0
, то x = 1/sqrt(n)
.Это приводит к итерации Ньютона:
x_(i+1) = x_i - f(x_i)/f'(x_i)
= x_i - (x_i^-2 - n)/(-2x_i^-3)
= x_i + (x_i - nx_i^3)/2
= x_i*(3/2 - 1/2 nx_i^2)
Обратите внимание, что (в отличие от итерации для квадратного корня), эта итерация для обратного квадратного корня не включает делений, поэтому в целом она намного эффективнее.
Я упомянул в вашем вопросе о делении, что вы должны смотреть на существующие библиотеки с плавающей запятой, а не заново изобретать колесо.Этот совет применим и здесь.Эта функция уже была реализована в существующих библиотеках с плавающей запятой.
Редактировать: спрашивающий, похоже, все еще сбит с толку, поэтому давайте поработаем с примером: sqrt(612)
.612
- это 1.1953125 x 2^9
(или b1.0011001 x 2^9
, если вы предпочитаете двоичный файл).Вытяните четную часть показателя степени (9), чтобы записать входные данные как f * 2^(2m)
, где m
является целым числом, а f
находится в диапазоне [1,4).Тогда у нас будет:
sqrt(n) = sqrt(f * 2^2m) = sqrt(f)*2^m
, применяя это сокращение к нашему примеру, получим f = 1.1953125 * 2 = 2.390625
(b10.011001
) и m = 4
.Теперь выполните итерацию Ньютона-Рафсона, чтобы найти x = 1/sqrt(f)
, используя начальное предположение 0,5 (как я отметил в комментарии, это предположение сходится для всех f
, но вы можете значительно улучшить результаты, используя линейное приближение в качестве исходного предположения):
x_0 = 0.5
x_1 = x_0*(3/2 - 1/2 * 2.390625 * x_0^2)
= 0.6005859...
x_2 = x_1*(3/2 - 1/2 * 2.390625 * x_1^2)
= 0.6419342...
x_3 = 0.6467077...
x_4 = 0.6467616...
Так что даже при (относительно плохом) начальном предположении мы получаем быструю сходимость к истинному значению 1/sqrt(f) = 0.6467616600226026
.
Теперь мы просто собираем конечный результат:
sqrt(f) = x_n * f = 1.5461646...
sqrt(n) = sqrt(f) * 2^m = 24.738633...
И проверьте: sqrt (612) = 24.738633 ...
Очевидно, что для правильного округления необходим тщательный анализ, чтобы обеспечить достаточную точность на каждом этапе вычислений.,Это требует тщательного учета, но это не ракетостроение.Вы просто сохраняете точные границы ошибок и распространяете их по алгоритму.
Если вы хотите исправить округление без явной проверки остатка, вам нужно вычислить sqrt (f) с точностью до 2p + 2 бит (где pточность источника и типа назначения).Тем не менее, вы также можете применить стратегию вычисления sqrt (f) к чуть более p битам, возвести в квадрат это значение и при необходимости отрегулировать конечный бит на единицу (что часто дешевле).
sqrt isприятно то, что это унарная функция, которая делает исчерпывающее тестирование на одинарную точность осуществимым на стандартном оборудовании.
Функцию OS X soft-float sqrtf
можно найти на opensource.apple.com, которая используеталгоритм, описанный выше (я написал, как это происходит).Он лицензирован в соответствии с APSL, который может или не может соответствовать вашим потребностям.