如何用牛顿法求一个数的平方根

简介: (一)导数与导函数导数设函数y=f(x)在点x0的某个邻域内有定义,当自变量x在x0处有增量Δx,(x0+Δx)也在该邻域内时,相应地函数取得增量Δy=f(x0+Δx)-f(x0);如果Δy与Δx之比当Δx→0时极限存在,则称函数y=f(x)在点x0处可导,并称这个极限为函数y=f(x)在点x0处的导数记作①f'(x0) ;②y'│x=x0 ;③│x=x0, 即导函数如果函数y=f(x)在开区间内每一点都可导,就称函数f(x)在区间内可导。

(一)导数与导函数

导数

设函数y=f(x)在点x 0的某个邻域内有定义,当自变量x在x 0处有增量Δx,(x 0+Δx)也在该邻域内时,相应地函数取得增量Δy=f(x 0+Δx)-f(x 0);如果Δy与Δx之比当Δx→0时极限存在,则称函数y=f(x)在点x 0处可导,并称这个极限为函数y=f(x)在点x 0处的导数记作 f'(x 0) ; y'│ x=x0
x=x0, 即

导函数

如果函数y=f(x)在开区间内每一点都可导,就称函数f(x)在区间内可导。这时函数y=f(x)对于区间内的每一个确定的x值,都对应着一个确定的导数,这就构成一个新的函数,称这个函数为原来函数y=f(x)的导函数,记作y'、f'(x)、dy/dx或df(x)/dx,简称导数。
导数是微积分的一个重要的支柱。牛顿及莱布尼茨对此做出了卓越的贡献。

几何意义

函数y=f(x)在x 0点的导数f'(x 0)的几何意义:表示函数曲线在点P 0(x 0,f(x 0))处的切线的斜率(导数的几何意义是该函数曲线在这一点上的切线斜率)。

 

 

 

(二)牛顿迭代法

 牛顿迭代法(Newton's method)又称为牛顿-拉夫逊方法(Newton-Raphson method),它是牛顿在17世纪提出的一种在实数域和复数域上近似求解方程的方法。多数方程不存在求根公式,因此求精确根非常困难,甚至不可能,从而寻找方程的近似根就显得特别重要。方法使用函数f(x)的泰勒级数的前面几项来寻找方程f(x) = 0的根。牛顿迭代法是求方程根的重要方法之一,其最大优点是在方程f(x) = 0的单根附近具有平方收敛,而且该法还可以用来求方程的重根、复根。另外该方法广泛用于计算机编程中。

 设r是f(x) = 0的根,选取x0作为r初始近似值,过点(x0,f(x0))做曲线y = f(x)的切线L,L的方程为y = f(x0)+f'(x0)(x-x0),求出L与x轴交点的横坐标 x1 = x0-f(x0)/f'(x0),称x1为r的一次近似值。

过点(x1,f(x1))做曲线y = f(x)的切线,并求该切线与x轴交点的横坐标 x2 = x1-f(x1)/f'(x1),称x2为r的二次近似值。重复以上过程,得r的近似值序列,其中x(n+1)=x(n)-f(x(n))/f'(x(n)),称为r的n+1次近似值,上式称为牛顿迭代公式。

 根据牛顿迭代的原理,可以得到以下的计算sqrt(n)的迭代公式:X(n+1)=[X(n)+p/Xn]/2。详细解释见下文。

一般性的编程方法如下:

1 double sqr(double n) { 
2     double k=1.0; 
3     while(abs(k*k-n)>1e-9) { 
4         k=(k+n/k)/2; 
5     } 
6     return k; 
7 }

(三)利用牛顿迭代法计算开平方根

这种算法的原理很简单,我们仅仅是不断用(x,f(x))的切线来逼近方程x^2-a=0的根。根号a实际上就是x^2-a=0的一个正实根,这个函数的导数是2x。也就是说,函数上任一点(x,f(x))处的切线斜率是2x。那么,x-f(x)/(2x)就是一个比x更接近的近似值。代入f(x)=x^2-a得到x-(x^2-a)/(2x),也就是(x+a/x)/2。

 过程如下:

首先随便猜一个近似值x,然后不断令x等于x和a/x的平均数,迭代个六七次后x的值就已经相当精确了。
例如,我想求根号2等于多少。假如我猜测的结果为4,虽然错的离谱,但你可以看到使用牛顿迭代法后这个值很快就趋近于根号2了:

(       4  + 2/   4     ) / 2 = 2.25
(    2.25  + 2/   2.25  ) / 2 = 1.56944..
( 1.56944..+ 2/1.56944..) / 2 = 1.42189..
( 1.42189..+ 2/1.42189..) / 2 = 1.41423..

 下面用C语言实现一遍:

 1 #include "stdio.h"
 2 #include "math.h"
 3 
 4 int main(void)
 5 {
 6     double n,y=1.0;
 7 
 8     printf("请输入一个需要求其平方根的数:");
 9     scanf("%lf",&n);
10 
11     // 反复代入 x(k+1) = 0.5[x(k)+n/x(k)]
12     while(fabs((1.0/2.0*(y+n/y))-y)>=0.00001)
13     {
14         y=1.0/2.0*(y+n/y);
15         printf( "y=%lf\n", y );
16     }
17     printf("平方根为%f\n",y);
18     return 0;
19 }

程序运行结果:

请输入一个需要求其平方根的数:2
y=1.500000
y=1.416667
y=1.414216
平方根为1.414216

请输入一个需要求其平方根的数:3
y=2.000000
y=1.750000
y=1.732143
y=1.732051
平方根为1.732051

 

 更快的方法

 1999年12月,美国id Software公司发布了名为“雷神之锤III”的电子游戏。它是第一个支持软件加速的游戏,取得了极大成功。(由于影响力过大,文化部于2004年将它列入了非法游戏名单)

雷神之锤III并不是id Software公司的第一次成功。早在1993年开始,这家公司就以“毁灭战士”系列游戏名闻天下。1995年,“毁灭战士”的安装数超过了当年微软的windows 95。据传比尔盖茨才曾经考虑买下id software。(id software公司后来被推出过“上古卷轴”系列的Bethesda公司买下)

id Software所取得的成功很大程度上要归功于它的创始人约翰·卡马克。马克尔也是一个著名的程序员,他是id Software游戏引擎的主要负责人。 回到刚才提到的雷神之锤,马克尔是开源软件的积极推动者,他于2005年公布了雷神之锤III的源代码。至此人们得以通过研究这款游戏引擎的源文件来查看它成功的秘密。

在其中一个名字为q_math.c的文件中发现了如下代码段。

 1 float Q_rsqrt( float number ) { 
 2     long i; float x2, y; const float threehalfs = 1.5F;
 3     x2 = number * 0.5F; 
 4     y = number; 
 5     i = * ( long * ) &y; // evil floating point bit level hacking 
 6     i = 0x5f3759df - ( i >> 1 ); // what the fuck? 
 7     y = * ( float * ) &i; 
 8     y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration 
 9     // y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
10     #ifndef Q3_VM #
11     ifdef __linux__ assert( !isnan(y) ); // bk010122 - FPE?
12     #endif
13     #endif return y; 
14 }

这段代码的作用就是求number的平方根,并且返回它的倒数。经测试这段代码比(float)(1.0/sqrt(x))快4倍。

 以雷神之锤III程序为蓝本可以写出比sqrt()更强大的求平方根函数:

 1     int sqrt(float x) {   
 2         if(x == 0) return 0;   
 3         float result = x;   
 4         float xhalf = 0.5f*result;   
 5         int i = *(int*)&result;   
 6         i = 0x5f375a86- (i>>1); // what the fuck?   
 7         result = *(float*)&i;   
 8         result = result*(1.5f-xhalf*result*result); // Newton step, repeating increases accuracy   
 9         result = result*(1.5f-xhalf*result*result);   
10         return 1.0f/result;   
11     }  

 

 参考:

http://www.nowamagic.net/librarys/veda/detail/2268

http://www.matrix67.com/blog/archives/361

http://blog.csdn.net/wangxiaojun911/article/details/18203333

http://www.cnblogs.com/huashanqingzhu/p/3615543.html

导数_百度百科

 

相关文章
|
6月前
|
机器学习/深度学习 人工智能 算法
【代数学作业1完整版-python实现GNFS一般数域筛】构造特定的整系数不可约多项式:涉及素数、模运算和优化问题
【代数学作业1完整版-python实现GNFS一般数域筛】构造特定的整系数不可约多项式:涉及素数、模运算和优化问题
127 0
|
6月前
|
机器学习/深度学习 人工智能 算法
【代数学作业1-python实现GNFS一般数域筛】构造特定的整系数不可约多项式:涉及素数、模运算和优化问题
【代数学作业1-python实现GNFS一般数域筛】构造特定的整系数不可约多项式:涉及素数、模运算和优化问题
120 0
|
3月前
|
算法 Go Python
[算法]计算斐波拉契数列
[算法]计算斐波拉契数列
|
5月前
|
机器学习/深度学习 算法 Serverless
利用无穷级数逼近计算幂运算与开根号——Python实现
使用泰勒级数逼近法,本文介绍了如何用Python计算特殊幂运算,包括分数次幂和开根号。通过定义辅助函数,如`exp`、`getN_minus_n`、`multi`和`getnum`,实现了计算任意实数次幂的功能。实验结果显示,算法能有效计算不同情况下的幂运算,例如`0.09^2`、`1^2`、`0.25^2`、`0.09^(0.5)`、`1^(0.5)`和`0.25^(0.5)`。虽然精度可能有限,但可通过调整迭代次数平衡精度与计算速度。
|
6月前
|
存储 算法 Python
【Python 百练成钢】高精度加法、阶乘计算、矩阵幂运算、矩阵面积交(2)
【Python 百练成钢】高精度加法、阶乘计算、矩阵幂运算、矩阵面积交(2)
|
6月前
|
存储 算法 Python
【Python 百练成钢】高精度加法、阶乘计算、矩阵幂运算、矩阵面积交(1)
【Python 百练成钢】高精度加法、阶乘计算、矩阵幂运算、矩阵面积交(1)
|
6月前
|
Python
【Python 百练成钢】高精度加法、阶乘计算、矩阵幂运算、矩阵面积交
【Python 百练成钢】高精度加法、阶乘计算、矩阵幂运算、矩阵面积交
|
6月前
|
算法 前端开发
前端算法-x 的平方根
前端算法-x 的平方根
|
C语言 C++
想要去欺负Leetcode的这些年—— 第一次 - 幂和对数
想要去欺负Leetcode的这些年—— 第一次 - 幂和对数
475 0
想要去欺负Leetcode的这些年—— 第一次 - 幂和对数
再学一道算法题:矩阵A乘以B
再学一道算法题:矩阵A乘以B
再学一道算法题:矩阵A乘以B