
牛顿叠代法
牛顿叠代法(Newton's method)又称为牛顿-拉夫逊(拉弗森)方法(Newton-Raphson method),它是牛顿在17世纪提出的一种在实数域和複数域上近似求解方程的方法。
基本介绍
- 中文名:牛顿叠代法
- 外文名:Newton's method
- 别称:牛顿-拉夫逊(拉弗森)方法
- 提出时间:17世纪
产生背景
多数方程不存在求根公式,因此求精确根非常困难,甚至不可能,从而寻找方程的近似根就显得特别重要。方法使用函式
的泰勒级数的前面几项来寻找方程
的根。牛顿叠代法是求方程根的重要方法之一,其最大优点是在方程
的单根附近具有平方收敛,而且该法还可以用来求方程的重根、复根,此时线性收敛,但是可通过一些方法变成超线性收敛。另外该方法广泛用于计算机编程中。



牛顿叠代公式
设
是
的根,选取
作为
的初始近似值,过点
做曲线
的切线
,
,则
与
轴交点的横坐标
,称
为
的一次近似值。过点
做曲线
的切线,并求该切线与x轴交点的横坐标
,称
为r的二次近似值。重複以上过程,得
的近似值序列,其中,
称为
的
次近似值,上式称为牛顿叠代公式。





















用牛顿叠代法解非线性方程,是把非线性方程
线性化的一种近似方法。把
在点
的某邻域内展开成泰勒级数
,取其线性部分(即泰勒展开的前两项),并令其等于0,即
,以此作为非线性方程
的近似方程,若
,则其解为
, 这样,得到牛顿叠代法的一个叠代关係式:
。









已经证明,如果是连续的,并且待求的零点是孤立的,那幺在零点周围存在一个区域,只要初始值位于这个邻近区域内,那幺牛顿法必定收敛。 并且,如果不为0, 那幺牛顿法将具有平方收敛的性能. 粗略的说,这意味着每叠代一次,牛顿法结果的有效数字将增加一倍。
叠代法也称辗转法,是一种不断用变数的旧值递推新值的过程,跟叠代法相对应的是直接法(或者称为一次解法),即一次性解决问题。叠代算法是用计算机解决问题的一种基本方法。它利用计算机运算速度快、适合做重複性操作的特点,让计算机对一组指令(或一定步骤)重複执行,在每次执行这组指令(或这些步骤)时,都从变数的原值推出它的一个新值。
利用叠代算法解决问题,需要做好以下三个方面的工作:
一、确定叠代变数
在可以用叠代算法解决的问题中,至少存在一个可直接或间接地不断由旧值递推出新值的变数,这个变数就是叠代变数。
二、建立叠代关係式
所谓叠代关係式,指如何从变数的前一个值推出其下一个值的公式(或关係)。叠代关係式的建立是解决叠代问题的关键,通常可以使用递推或倒推的方法来完成。
三、对叠代过程进行控制
在什幺时候结束叠代过程?这是编写叠代程式必须考虑的问题。不能让叠代过程无休止地执行下去。叠代过程的控制通常可分为两种情况:一种是所需的叠代次数是个确定的值,可以计算出来;另一种是所需的叠代次数无法确定。对于前一种情况,可以构建一个固定次数的循环来实现对叠代过程的控制;对于后一种情况,需要进一步分析得出可用来结束叠代过程的条件。
其他叠代算法
欧几里德算法
最经典的叠代算法是欧几里德算法,用于计算两个整数a,b的最大公约数。其计算原理依赖于下面的定理:
定理:gcd(a,b) = gcd(b,a mod b)
证明:a可以表示成a = kb + r,则r = a mod b。假设d是a,b的一个公约数,则有 a%d==0,b%d==0,而r = a - kb,因此r%d==0 ,因此d是(b,a mod b)的公约数
同理,假设d 是(b,a mod b)的公约数,则 b%d==0,r%d==0 ,但是a = kb +r ,因此d也是(a,b)的公约数。
因此(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证。
欧几里德算法就是根据这个原理来做的,欧几里德算法又叫辗转相除法,它是一个反覆叠代执行,直到余数等于0停止的步骤,这实际上是一个循环结构。其算法用C语言描述为:
int Gcd_2(int a,int b)/*欧几里德算法求a,b的最大公约数*/{if (a<=0 || b<=0)/*预防错误*/return 0;int temp;while (b > 0)/*b总是表示较小的那个数,若不是则交换a,b的值*/{temp = a % b;/*叠代关係式*/a = b;b = temp;}return a;}
从上面的程式我们可以看到a,b是叠代变数,叠代关係是temp = a % b;根据叠代关係我们可以由旧值推出新值,然后循环执a = b; b = temp;直到叠代过程结束(余数为0)。在这里a好比那个胆小鬼,总是从b手中接过位置,而b则是那个努力向前沖的先锋。
斐波那契数列
还有一个很典型的例子是斐波那契(Fibonacci)数列。斐波那契数列为:0、1、1、2、3、5、8、13、21、…,即 fib⑴=0; fib⑵=1;fib(n)=fib(n-1)+fib(n-2) (当n>2时)。
在n>2时,fib(n)总可以由fib(n-1)和fib(n-2)得到,由旧值递推出新值,这是一个典型的叠代关係,所以我们可以考虑叠代算法。
int Fib(int n) //斐波那契(Fibonacci)数列{if (n < 1)/*预防错误*/return 0;if (n == 1 || n == 2)/*特殊值,无需叠代*/return 1;int f1 = 1,f2 = 1,fn;/*叠代变数*/int i;for(i=3; i<=n; ++i)/*用i的值来限制叠代的次数*/{fn = f1 + f2; /*叠代关係式*/f1 = f2;//f1和f2叠代前进,其中f2在f1的前面f2 = fn;}return fn;}
C语言代码
double func(double x) //函式{ return x*x*x*x-3*x*x*x+1.5*x*x-4.0;}double func1(double x) //导函式{ return 4*x*x*x-9*x*x+3*x;}int Newton(double *x,double precision,int maxcyc) //maxcyc 叠代次数{ double x1,x0; int k; x0=*x; for(k=0;k<maxcyc;k++) { if(func1(x0)==0.0)//若通过初值,函式返回值为0 { printf("叠代过程中导数为0!\n"); return 0; } x1=x0-func(x0)/func1(x0);//进行牛顿叠代计算 if(fabs(x1-x0)<precision || fabs(func(x1))<precision)//达到结束条件 { *x=x1; //返回结果 return 1; } else //未达到结束条件 { x0=x1; //準备下一次叠代 } } printf("叠代次数超过预期!\n"); //叠代次数达到,仍没有达到精度 return 0;}int main(){ double x,precision; int maxcyc; printf("输入初始叠代值x0:"); scanf("%lf",&x); printf("输入最大叠代次数:"); scanf("%d",&maxcyc); printf("叠代要求的精度:"); scanf("%lf",&precision); if(Newton(&x,precision,maxcyc)==1) //若函式返回值为1 { printf("该值附近的根为:%lf\n",x); } else //若函式返回值为0 { printf("叠代失败!\n"); } return 0;}
C++代码
//此函式是用来求一元3次方程ax^3+bx^2+cx+d=0的解//比如 x^3-27=0,我们就可以输入1 0 0 -27,这样我们就可以得到一个解#include<iostream>#include<cmath>using namespace std;int main(){double diedai(double a,double b,double c,double d,double x);double a,b,c,d;double x=10000.0;cout<<"请依次输入方程四个係数:";cin>>a>>b>>c>>d;x=diedai(a,b,c,d,x);cout<<x<<endl;return 0;}double diedai(double a,double b,double c,double d,double x){while(abs(a*x*x*x+b*x*x+c*x+d)>0.000001){x=x-(a*x*x*x+b*x*x+c*x+d)/(3*a*x*x+2*b*x+c);}return x;}
可以得到一元3次方程3个解的程式(原创,超最佳化):
#include<iostream>#include<vector>using namespace std;vector<double >v;//stl vector链型数组vector<double >::iterator it;//vector叠代器int x0=5;double a,b,c,d;double abs(double y){ while(y<0) y=-y; return y;}double f(double x){ return a*x*x*x+b*x*x+c*x+d;}double fd(double x){ return 3*a*x*x+2*b*x+c;}bool u;//用来判断是否重複void newton(int a1,int b1,int c1,int d1){ for(x0=-5000;x0<=5000;x0++)//在一个大区域中逐个点用牛顿法,可找出大多数3次方程所有根 { double x1=x0; while(abs(f(x1))>0.001) { double x=x1; x1=x-f(x)/fd(x); } for( it=v.begin();it!=v.end();it++) { if(abs((*it-x1))<0.01) {u=1; break;} } if(u!=1&&x1<1000000000) { cout<<x1<<" "; v.push_back(x1);//把已得到的解添加到vector,用于防止重複 } u=0; } }int main(){ cin>>a>>b>>c>>d; newton(a,b,c,d);}
matlab代码
定义函式
function y=f(x)
y=f(x);%函式f(x)的表达式
end
function z=h(x)
z=h(x);%函式h(x)的表达式
end
主程式
x=X;%叠代初值
i=0;%叠代次数计算
while i<= 100%叠代次数
x0=X-f(X)/h(X);%牛顿叠代格式
if abs(x0-X)>0.01;%收敛判断
X=x0;
else break
end
i=i+1;
end
fprintf('\n%s%.4f\t%s%d','X=',X,'i=',i) %输出结果
Python代码
Python代码以实例展示求解方程
的根。

def f(x): return (x-3)**3 '''定义 f(x) = (x-3)^3'''def fd(x): return 3*((x-3)**2) '''定义 f'(x) = 3*((x-3)^2)'''def newtonMethod(n,assum): time = n x = assum Next = 0 A = f(x) B = fd(x) print('A = ' + str(A) + ',B = ' + str(B) + ',time = ' + str(time)) if f(x) == 0.0: return time,x else: Next = x - A/B print('Next x = '+ str(Next)) if A - f(Next) < 1e-6: print('Meet f(x) = 0,x = ' + str(Next)) '''设定叠代跳出条件,同时输出满足f(x) = 0的x值''' else: return newtonMethod(n+1,Next)newtonMethod(0,4.0) '''设定从0开始计数,x0 = 4.0'''
Java代码
Java实现开平方的牛顿叠代法. 求
的算术平方根就是求
的正根, 得叠代公式:
. 代码中取初始值
, 误差控制在
.





public static double sqrt(double c) { if (c < 0) {return Double.NaN; } double e = 1e-15; double x = c; double y = (x + c / x) / 2; while (Math.abs(x - y) > e) { x = y; y = (x + c / x) / 2; } return x;}
JavaScript代码
/*** @function newtonMethod 该函式是牛顿叠代法的js实现他可以用于求任意一元高次方程的解。(简单版)* @param fn 要求根的函式* @param dfn 要求根的函式的导函式* @param x0 在函式x定义域上任意取的一个x值x0* @param n 期望叠代的次数* @return 该方程的近似解* */function newtonMethod(fn, dfn, x0, n){ const y = fn(x0) // 在函式有效区间内选取任意 x0 求出点 (x0,y) 其中 y= fn(x0) const k = dfn(x0) // 使用导函式求出过 点(x0,y) 的切线斜率 k const b = y - k * x0 // 将点(x0,y) 代入直线方程 y=kx+b 求出常数 b 。 const x = (0 - b) / k // 将 y=0代入直线方程 y=kx+b 求出该方程的一次近似解 x if(--n > 0){ return newtonMethod(fn, dfn, x, n) // 当n趋于无穷大时得到该方程的精确解 } return x}// 化简函式 (simplify)function NTMethod(fn = _=>_, dfn = _=>1, x0 = 0, n = 1){ const x = x0 - fn(x0) / dfn(x0) if(n === 1){ return x // 返回一个关于函式 fn(x) 的近似解 } return NTMethod(fn, dfn, x, --n)}
Fortran代码
program newton
implicit none
real::a
real::b
real::fb
real::counter
integer::n
!real,parameter::zero=0.00001
real::fx,fx1
real::df
write(*,*)"enter a number:"
read(*,*)a
do counter=1,a-1
fx=sin(counter)
fx1=sin(counter+1)
if (fx*fx1<0) then
df=cos(counter)
fx=sin(counter)
write(*,*)"初始值取:"
write(*,*)counter
do n=1,25,1
b=counter-fx/df
fb=sin(b)
end do
write(*,*)"数值解:"
write(*,*)b
end if
end do
stop
end program
