计算迭代函数的不动点c语言,非线性方程的数值计算方法实验

非线性方程的数值计算方法实验

一、实验描述:

在科学研究和工程实践中,经常需要求解大量的非线性方程。本实验正是通过计算机的程序设计,使用迭代法、波尔查诺二分法、试值法、牛顿-拉夫森法和割线法,来实现非线性方程的求解。

本实验中通过对各种方法的实践运用,可以比较出各种方法的优缺点。并且,通过完成实验,可加深对各种方法的原理的理解,熟悉掌握C 语言在这些方法中的运用。

二、实验内容:

1、 求函数g (x)=x x -cos(x)的不动点(尽可能多)近似值,答案

精确到小数点后12位;

2、 如果在240个月内每月付款300美元,求解满足全部年

金A 为500000美元的利率I ,的近似值(精确到小数点

后10位)。

3、 利用加速牛顿-拉夫森算法,用其求下列函数M 阶根p

的近似值。

(a)、f(x)=(x-2),M=5,p=2,初始值p 0=1。 5

(b)、f(x)=sin(x) ,M=3,p=0,初始值p 0=1。

(c)、f(x)=(x-1)ln(x),M=2,p=1,初始值p 0=2。

4、 设投射体的运动方程为: 3

y=f(t)=9600(1-e

-t/15)-480t

x=r(t)=2400(1-e-t/15)

(a) 求当撞击地面时经过的时间,精确到小数点后10位。

(b)求水平飞行行程,精确到小数点后10位。

三、实验原理:

(1)、不动点迭代法:它是一种逐次逼近的方法, 即用某个固定公式反复校正根的近似值, 使之逐步精确化, 最后得到满足精度要求的结果。它利用计算机运算速度快,适合做重复性操作的特点,让计算机对一个函数进行重复执行,在每次执行这个函数时,都从变量的原值推出它的一个新值,直至推出最终答案为止。

迭代法一般可用于寻找不动点,即:存在一个实数P ,满足P=g(P),则称P 为函数g(x)的一个不动点。且有定理:若g(x)是一个连续函数,且 p n ∞n=0是由不动点迭代生成的序列。如果lim n →∞p n =P , 则P 是g(x)的不动点。所以,不动点的寻找多用迭代法。

(2)、波尔查诺二分法:

起始区间[a,b]必须满足f(a)与f(b)的符号相反的条件。由于连续函数y=f(x)的图形无间断,所以它会在零点x=r处跨过x 轴,且r 在区间内。通过二分法可将区间内的端点逐步逼近零点,直到得到一个任意小的包含零点的间隔。

二分法定理:设f ∈C (a,b),且存在数r ∈[a,b]满足f(r)=0。如果f(a)和f(b)的符号相反,且 c n ∞n=0为二分法生成的中点序列,则:

r −c n ≤

b −a 2其中n=0,1,… (1)

这样,序列 c n ∞n=0收敛到零点x=r即可表示为:

lim n →∞c n =r (2)

(3)、试值法:

假设一个函数中,有f(a)和f(b)符号相反。二分法使用区间[a,b]的中点进行下一次迭代。如果找到经过点(a,f(a))和(b,f(b))的割线L 与x 轴的交点(c,0),则可得到一个更好的近似值。为了寻找值c ,定义了线L 的斜率m 的两种表示方法,一种表示方法为:

m=f b −f(a)

b −a 这里使用了点(a,f(a))和(b,f(b))。另一种表示方法为:

0−f(b)

c −b m=

这里使用了点(c,0)和(b,f(b))。

使式(3)和式(4)的斜率相等,则有:

f b −f(a)

b −a =0−f(b)

c −b

为了更容易求解c ,可进一步表示为:

f b (b−a) c=b-f b −f(a)

这样会出现3种可能性:

如果f(a)和f(c)的符号相反,则在[a,c]内有一个零点。 如果f(c)和f(b)的符号相反,则在[c,b]内有一个零点。

如果f(c)=0,则c 是零点。

然后,可按二分法的方法进行下一步运算。

(4)、牛顿-拉夫森法:

此法根据,牛顿-拉夫森定理:设f ∈C 2[a,b],且存在数p ∈[a,b], 满足f(p)=0。如果f (p)≠0, 则存在一个数δ>0,对任意初始近似值p 0∈[p-δ,p+δ],使得由如下迭代定义的序列 p k ∞k=0收敛到p:

f(pk −1) p k =g(pk-1)= pk-1-其中f (pk −1) k=1,2,…(7)

其中,函数g(x)由如下定义:

f(x)g(x)=x--f (x)

且被称为牛顿-拉夫森迭代函数。由于f(p)=0,显然g(p)=p。这样,通过寻找函数的不动点,可以实现寻找方程f(x)=0的根的牛顿-拉夫森迭代。

附:定理(牛顿-拉夫森迭代的加速收敛) :

设牛顿-拉夫森算法产生的序列线性收敛到M 阶根x=p,其中M >1,则牛顿-拉夫森迭代公式:

f(pk −1) p k =p k −1-M f (pk −1)

(5)、割线法:

割线法包含的公式与试值法的公式一样,只是在关于如何定义每个后续项的逻辑判定上不一样。需要两个靠近点(p,0)的初始点(p 0,f(p 0) ) 和(p 1,f(p 1)) 。

可根据两点迭代法公式,得到一般项:

f p k (pk −p k −1) p k+1=g(p k , p k −1)=p k - (10) f p k −f(pk −1)

四、结果计算及分析:

1、函数g(x)=x

(a)计算结果: x-cos(x) 的不动点的迭代(迭代法) :

(b)结果分析:

此题经过matlab 图形仿真,可以看出其解的大致范围在

[0.8,1.2]之间。此结果是在取p 0=0.879的情况下得出的,其误差精

度取为0.[1**********]1。从迭代过程的误差收敛速度可以看出不动点迭代的误差收敛较慢,所需迭代次数较多。

2、满足条件的利率I 的计算(试值法) :

(a)、计算结果:

(b)、结果分析:

此题经过一定的计算分析,将书中所给公式结合题中的条件3600I [ 1+ 12I 240-1]-500000=0,求解其

中的I 即为利率。又经过一定的计算分析,取其初始计算区间为

[0.1,0.2],误差精度取为0.[1**********]1。

从其误差收敛的速度可以看出,试值法的误差收敛速度快,所需的迭代次数少。

3、利用加速牛顿-拉夫森算法,求函数f(x)=(x-2)、f(x)=sin(x) 和f(x)=(x-1)ln(x)的M 阶根p 的近似值。其中每个函数的M 、p 0和最终结果p 已给出。

(a)、计算结果: 35

(b)、结果分析:

由于C 语言函数库中没有求导功能函数,而此题所要求用的加

f(pk −1) 速牛顿-拉夫森算法的计算公式 p k =p k −1-M 中要用到题中f (pk −1)

所给函数的导函数,所以求出它们的导函数分别为f (x)=5(x-2)2, f (x)=3x2cos(x3) 和f (x)=In(x)-1-

为0.[1**********]。

从输出结果中可以大致判断出,加速牛顿-拉夫森法的收敛速1x 此题的误差精度取度非常快。

4、给出投射物体的运动方程y=f(t)=9600(1-e

-t/15

)-480t

和x=r(t)=2400(1-e

(割线法)

(a)计算结果: -t/15) 求物体落地时经过的时间和水平飞行程。

(b)、结果分析:

此题用了割线法的思路进行程序设计,由于割线法的公式要求,需要给出t 0,t 1 两个初始值。经过一定的分析,给出t 0=5.0,t 1=15.0,

误差精度设为0.0000000001。

从输出结果中可以看出,割线法的误差收敛速度比较快,所需的迭代次数比较少。

五、实验结果分析:

经过以上四个实验的比较分析,结合书上的实例与原理分析,可以得出。不动点迭代法比起其他的迭代法,迭代速度慢、次数多。试值法的迭代次相对少一些,但若对其初始区间估算得太大的话,会导致迭代步数增多,甚至会导致发散。割线法比试值法要快得多,可以达到相对较高的精度,且在其迭代过程中每步只需一次新的函数赋值,其收敛阶一般能达到1.1618。加速牛顿-拉夫森法再求多重根时速度很快,收敛阶能达到2。

附件:

第一题:

#include

#include

#include//为了调用FLT_EPSILON,防止出现分母为零的情况。//

#define N 1000//保证有足够多的运算次数能达到比较精确的结果,且便于修改。//

#define pre 0.[1**********]01//使循环能够在达到某一误差精度后停下来。//

double main()

{

double p[N],m,err[N],relerr[N];

int k,n;

p[0]=0.879;//给定一个合理的初始值以此来进行迭代。// for(k=0;k

{

m=p[k]-cos(p[k]);

p[k+1]=pow(p[k],m);//进行迭代的方程,由书上给出。// err[k]=fabs(p[k+1]-p[k]);//对绝对误差的运算。// relerr[k]=err[k]/(fabs(p[k+1])+FLT_EPSILON);//对相对误差的运算。//

n=k;//把k 赋给n, 使下面输出时能够在合适的时候停下来。

//

if(err[k]

}for(k=0;kprintf("\nX[%d]=%14.12f err[%d]=%14.12frelerr[%d]=%14.12f",k,p[k],k,err[k],k,relerr[k]);//对迭代点及误差的输出。//getch();return 0;}

第二题:#include#include#include#define N 10000#define pre 0.[1**********]1//使循环能够在达到某一误差精度后停下来。//double main(){double f(double x);double a[N],b[N],I[N],err[N],relerr[N];int i,n;a[0]=0.10,b[0]=0.20;//预估它们的初始区间//for(i=0;i{I[i]=b[i]-(f(b[i])*(b[i]-a[i]))/(f(b[i])-f(a[i]));//试值法公式,有书上给出。//if((f(a[i])*f(I[i]))>0)a[i+1]=I[i],b[i+1]=b[i];//根据试值法,判断区间。//elsea[i+1]=a[i],b[i+1]=I[i];//根据试值法,判断区间。//err[i]=fabs(I[i]-I[i-1]);//对绝对误差的运算。//relerr[i]=err[i]/(fabs(I[i])+FLT_EPSILON);//对相对误差的运算。//n=i;//将i 值赋给n, 使输出能够在合适的时候停下来。// if(err[i]

}err[0]=I[0]-0;//定义初始误差,便于下面输出。//relerr[0]=err[0]/(fabs(I[0])+FLT_EPSILON);//定义初始误差,便于下面输出。//for(i=0;iprintf("\n I[%d]=%12.10f err[%d]=%12.10frelerr[%d]=%12.10f",i,I[i],i,err[i],i,relerr[i]);//输出利率的计算过程。//getch();return 0;}double f(double x){return((3600/x)*(pow(1+x/12,240)-1)-500000);//此题的计算公式,由书上给出。//}

第三题:#include#include#include//为了调用FLT_EPSILON,防止出现分母为零的情况。//#define pre 0.[1**********]//使循环能够在达到某一误差精度后停下来。//#define N 1000//迭代次数,以保证能得到最精确的值。//double main(){double fa(double x);//声明fa 函数。//double fb(double x);//声明fb 函数。//double fc(double x);//声明fc 函数。//double a[N],b[N],c[N],err[N];//定义结果数组,与误差数组。//int k,i,j,m;a[0]=1.0,b[0]=1.0,c[0]=2.0;//赋初始值,由书上给出。// for(k=0;k{a[k+1]=a[k]-5.0*fa(a[k]);//加速牛顿-拉夫森公式,见书上P64。下同。//err[k]=fabs(2.0-a[k+2]);//对绝对误差的运算。k 加2,以保证下面输出时其有足够多的值输出。//i=k;//将循环停止时的k 值赋给i ,便于在下面输出时有恰当的值使输出停止。下同。//if(err[k]

}for(k=0;k{b[k+1]=b[k]-3.0*fb(b[k]);err[k]=fabs(0.0-b[k]);//对绝对误差的运算。//j=k;if(err[k]

}for(k=0;k{c[k+1]=c[k]-2.0*fc(c[k]);err[k]=fabs(1.0-c[k]);//对绝对误差的运算。//m=k;if(err[k]

}if(i>j) j=i;if(m>j) m=j;//对i,m,j 进行比较,并求出最大值,并用于输出。//for(k=0;kprintf("\na[%d]=%12.10f b[%d]=%12.10fc[%d]=%12.10f",k,a[k],k,b[k],k,c[k]);getch();return 0;}double fa(double x){return((1.0/5.0)*(x-2.0));//书上所给的计算要求的公式。下同。//}double fb(double x){return((1.0/(3.0*x*x))*tan(x*x*x));}double fc(double x){return(((x-1.0)*log(x))/(log(x)+1.0-1.0/x));}

第四题:#include#include//方便各种数学函数的调用。//#include//为了调用FLT_EPSILON,防止出现分母为零的情况。//#define N 1000//保证有足够多的运算次数能达到比较精确的结果,且便于修改。//#define pre 0.0000000001//使循环能够在达到某一误差精度后停下来。//double main(){double f(double t);//声明f 函数。//double r(double t);//声明r 函数。//double t[N],err[N],relerr[N],dif[N];//使结果能够以数组形式输出,便于分析。//char ch1[]="t",ch2[]="dif",ch3[]="err",ch4[]="relerr";//对输出进行标注。//int k,i;//定义i ,以便在达到所需精度之后,对所有结果以及对最终结果进行输出。//t[0]=5.0,t[1]=15.0;//给出任意合法的初始值。//err[0]=fabs(t[1]-t[0]),relerr[0]=err[0]/fabs(t[1]+FLT_EPSILON),dif[0]=t[1]-t[0];//对各个结果的初始值进行运算。//for(k=1;k{t[k+1]=t[k]-(f(t[k])*(t[k]-t[k-1]))/(f(t[k])-f(t[k-1]));//用割线法给出的公式进行运算,以求出最终结果。//dif[k]=t[k+1]-t[k];err[k]=fabs(dif[k]);//对绝对误差的运算。//relerr[k]=err[k]/(fabs(t[k+1])+FLT_EPSILON);//对相对误差的运算。//i=k+1;//在达到所需精度后,在往后加一位得到更精确的结果。//if(err[k]

}printf(" %s %s %s %s",ch1,ch2,ch3,ch4);//对输出进行标记。//for(k=0;kprintf("\n%15.10f%15.10f%15.10f%15.10f",t[k],dif[k],err[k],relerr[k]);//输出各结果。//

printf("\n");//使输出间空出一行,便于观察。//

printf("\n 当物体撞击地面时经过了%12.10f秒。

",t[i]);//输出最终所需时间。//

printf("\n 物体水平飞行了%15.10f米。",r(t[i]));//调用r 函数,输出最终在水平方向的飞行行程。//

getch();

return 0;

}

double f(double t)

{

return(9600*(1-exp(-t/15))-480*t);//物体在Y 方向的路程与时间的关系,由书上给出。//

}

double r(double t)

{

return(2400*(1-exp(-t/15)));//物体在x 方向的路程与时间的关系,由书上给出。//

}

你可能感兴趣的:(计算迭代函数的不动点c语言)