`
海王子1994
  • 浏览: 43719 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Matlab编写二分法及牛顿迭代法

 
阅读更多

      谈到单根区间上方程求根的近似算法,我们第一印象就是高中的时候接触的二分法,正如其名称,二分法就是通过每次把f(x)的零点所在小区间收缩一半的方法,使区间的两个端点逐步迫近函数的零点,以求得零点的近似值。

 

大概步骤如下:

 

假定f(x)在区间(x,y)上连续
先找到a、b属于区间(x,y),使f(a),f(b)异号,说明在区间(a,b)内一定有零点,然后求f[(a+b)/2],
现在假设f(a)<0,f(b)>0,a<b
①如果f[(a+b)/2]=0,该点就是零点,
②如果f[(a+b)/2]<0,则在区间((a+b)/2,b)内有零点,(a+b)/2>a,从①开始继续使用中点函数值判断。
③如果f[(a+b)/2]>0,则在区间(a,(a+b)/2)内有零点,(a+b)/2<b,从①开始继续使用中点函数值判断。
 
此外还有另外一种方法,叫牛顿迭代法,也称牛顿切线法,它也是一种近似算法,内容如下:
设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的一次近似值,如果|f(x1)-0|小于指定的精度,那么继续过点(x1,f(x1))做曲线y=f(x)的切线,并求该切线与x轴的横坐标 x2=x1-f(x1)/f'(x1)称x2为r的二次近似值,重复以上过程。得r的近似值序列{Xn},其中Xn 1=Xn-f(Xn)/f'(Xn),称为r的n 1次近似值。上式称为牛顿迭代公式。
 如图:

 
现用matlab编写两种方法,比较它们的收敛速度。
1.先给出需要求根函数:
function f=cal(x)
f=exp(-0.005*x)*cos(sqrt(2000-0.01*x*x)*0.05)-0.01;
end
 2.二分法函数:
function [xvalue,gap,fx,count]=bisect(a,b,nmax,eps,fun)
% xvalue--自变量迭代值  gap--区间长度   fx--函数值   count--计数
% nma--所允许执行的最大次数,防止死循环  eps--允许的误差   fun--调用的函数名
err=eps+1;
count=0;%初始化计数值为0
xvalue=[];%xvalue向量存储变量x的值
gap=[];%gap向量存储误差值
fx=[];%fx向量存储函数值
while(err>eps&&count<nmax)
    %当误差err大于所给的误差长度或者计数小于允许运行次数时,执行算法
    
    count=count+1;%计数加1
    c=(a+b)/2;%计算中间值
    x=c;
    xvalue=[xvalue;x];%将自变量迭代值存入xvalue矩阵
    fc=feval(fun,x);%将自变量代入cal函数得到的函数值赋给fc
    fx=[fx;fc];%将fc函数值存入fx矩阵
    x=a;
    %判断根在哪个区域
    if(fc*feval(fun,x)<0)
        b=c;
    else
        a=c;
    end
    err=abs(b-a);%误差长度
    gap=[gap;err];
end
disp('  次数        自变量             区间长           函数值         ')
%输出相应数据
for i=1:count
    fprintf('%2d        %10.6f        %10.6f       %10.6f      \n  ',i,xvalue(i),gap(i),fx(i))
end

 3.牛顿迭代法函数:
function [xvalue gap fx,count]=Newton(x0,nmax,eps,fname)
%初始化xvalue,gap,fx向量
xvalue=[];
gap=[];
fx=[];
count=0;%初始化计数为0
x1=x0+1;
m=eps+1;
while(m>eps&&count<nmax)
    count=count+1;%计数
    f=feval(fname,x0);%得到f(x0)函数值
    xvalue=[xvalue;x0];
    fx=[fx;f];
    x1=x0-f/df(x0);
    gap=[gap;x1-x0];
    m=abs(x1-x0);
    x0=x1;%x1传值给x0,准备进行下一次迭代
   
end
disp('次数        自变量             区间长           函数值         ')
%输出数据
for i=1:count
    fprintf('%2d        %10.6f        %10.6f       %10.6f        \n',i,xvalue(i),gap(i),fx(i))
end
 4.牛顿迭代法中需要用的求导函数:
function h=df(x)
%求函数的导函数

syms R  %符号化R
y=cal(R);%调用cal函数
dy=diff(y);%求cal函数的导函数
h=subs(dy,R,x);%获得cal函数的导函数取x的值
end
 5.脚本:
%分别调用二分法和牛顿迭代法 
disp('二分法运行如下:')
bisect(0,400,50,0.000001,@cal);
disp('                   ')
disp('牛顿迭代法运行如下:')
Newton(200,50,0.000001,@cal);
 
运行结果如图:


 
这样我们就大概完成了,可以发现:牛顿迭代法的收敛速度明显比二分法要快得多,以后遇到求根时可以选择用牛顿迭代法,提高效率!!

 
  • 大小: 4.8 KB
  • 大小: 5.6 KB
  • 大小: 12.7 KB
1
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics