牛顿迭代公式
设是
的根,选取
作为
的初始近似值,过点
做曲线
的切线
,
,则
与
轴交点的横坐标
,称
为
的一次近似值。过点
做曲线
的切线,并求该切线与x轴交点的横坐标
,称
为
的二次近似值。重复以上过程,得
的近似值序列,其中,
称为
的
次近似值,上式称为牛顿迭代公式。
用C语言写出:
#include<stdio.h>
#include<math.h>
double newton_sqrt(double a);
int main()
{
double a,s;
printf("请输入需要计算平方根的数:");
scanf("%lf", &a);
s=newton_sqrt(a);
printf("%lf的平方根近似值为%8.5f", a,s);
return 0;
}
double newton_sqrt(double a)
{
double x = 1.0;//初始值
while (1)
{
double next_x = 0.5 * (x + a / x);//牛顿迭代法
if (fabs(next_x - x) <1e-7)//判断精度
{
return next_x;
}
x = next_x;
}
return 0;
}
但在我网上冲浪时,看到了来自Greg.Walsh格雷格·沃什的平方根倒数快速算法。
Amazing!!!
计算平方根是3D程序的基础。为了简化平方根代码,沃什开始了研究。
他利用《计算机组成原理》中对浮点数的存储方式(408第二章)(IEEE754标准)
,但这复杂程度不亚于牛顿法。
但沃什祭出对数大杀器
再利用近似值进行
转换
我们可以清楚看到这是二进制的表示方式
浮点数y,以二进制存储的Y
这已经很强了,但沃什不满足,他进行了又一次优化。
设a为y的平方根倒数
把a 和y换为它们的二进制形式A和Y
二进制形式
转换为十六进制为5f400000
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;
}
其中0x5f3759df是对5f400000的修正
其中还有程序员之神约翰·卡马克的这句婉转悠扬的注释what the fuck?