数值计算(二分法、简单迭代法、Newton迭代法、弦截法(割线法、双点弦法))
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
附录:源程序清单
#include<iostream>
#include<math.h>
usingnamespacestd;
doublefoot=0.3;//定义寻根步长
inta=-8,b=8;
double*rn=newdouble[5];//解的区间
double*r=newdouble[5];//方程近似解
18
1.69027
5
1.68278
12
1.69006
19
1.69028
6
1.68573
13
1.69015
20
1.69028
7
1.68753
14
1.6902
表2-3
牛顿
初值-1.5结果x=-1.50507
k
xk
k
xk
1
-1.5
4
-1.50504
2
-1.50471
5
-1.505063Βιβλιοθήκη -1.504976
-1.50507
表3-1
初值-1结果x=-1.50507
k
x
1
-1
2
-1
表3-2
初值1.6结果x=1.69028
k
xk
k
xk
1
1.6
5
1.69024
2
1.68602
6
1.69027
3
1.68893
7
1.69028
4
1.68985
8
1.69028
表3-3
双点
区间[-1.6,-1.3]结果x=-1.50507
k
xk
f(xk)
3并重复上述步骤,直达达到精度要求,则mid为方程的近似解。
2.2 简单迭代法
思想:迭代法是一种逐次逼近的方法,它是固定公式反复校正跟的近似值,使之逐步精确,最后得到精度要求的结果。
步骤:1.构造迭代公式f(x),迭代公式必须是收敛的。
2.计算x1,x1=f(x0).
3.判断|x1-x0|是否满足精度要求,如不满足则重复上述步骤。
//计算函数的一阶导数fderivatives(double x)
doublefderivatives(doublex){
return5*pow(x,4)-9*(x,2)+1;
}
//构造牛顿迭代公式newtonitera(double x)
doublenewtonitera(doublex){
if(fderivatives(x)==0)return-1;//若导数为0则停止迭代
12
-1.50489
18
-1.50505
表2-1
初值-1
k
x
1
-1
2
-1
表2-2
初值1.6结果x=1.69028
k
xk
k
xk
k
xk
1
1.6
8
1.68862
15
1.69023
2
1.65669
9
1.68927
16
1.69025
3
1.66987
10
1.68967
17
1.69027
4
1.6779
11
1.68991
k
xk
f(xk)
1
-1.01393
0.0415678
2
-1.0002
0.000607777
3
-0.999999
-3.11969e-006
4
-1
2.11001e-010
表4-2
区间[1.5,1.8]结果x=1.69028
k
xk
f(xk)
1
1.64403
-0.676455
2
1.68071
-0.151106
k
xk
k
xk
k
xk
1
-1.5
7
-1.50435
13
-1.50493
2
-1.50217
8
-1.50453
14
-1.50497
3
-1.50287
9
-1.50466
15
1.50499
4
-1.50341
10
-1.50476
16
-1.50501
5
-1.50381
11
-1.50483
17
-1.50504
6
-1.50412
cout<<x0<<endl;
doublex1=fitera(x0);
while(fabs(x1-x0)>precision){
x0=x1;
x1=fitera(x0);//没有到达精度要求继续迭代
cout<<x1<<endl;
}
returnx1;//返回最终结果
}
//===============牛顿迭代法==================
double result=0;
cout<<"有根区间为["<<rn[i]<<" "<<rn[i]+foot<<"]"<<endl;
double x0 =r[i]; //取得初值
result=itera(x0); //带入公式
cout<<"求得近似解为"<<result<<endl;
else
returnx-(f(x)/fderivatives(x));
}
//牛顿迭代
doublenewton(doublex0){
doublex1=newtonitera(x0);
while(fabs(x1-x0)>precision){
x0=x1;
if(newtonitera(x0)==-1)break;
要求:讨论求解的全过程,对所用算法的局部收敛性,优缺点等作分析及比较,
第
2.1二分法
思想:在函数的单调有根区间,将有根区间不断的二分,寻找方程的解。
步骤:1.取中点mid=(x0+x1)/2
2.若f(mid)=0,则mid为方程的根,否则比较与两端的符号,若与f(x0)
异号,则根在[x0,mid]之间,否则在[mid,x1]之间。
3
1.69126
0.0157988
4
1.69027
-0.000313515
5
1.69028
-6.3006e-007
表4-3
从测试结果可以看出二分法和简单迭代法的收敛速度远大于牛顿迭代和弦截法的收敛速度。二分法和简单迭代法的公式易于构造和计算,牛顿迭代法虽然收敛高,但要求导数,计算的复杂度高!双点弦法随稍慢于牛顿跌代法,可以用差商代替牛顿迭代法中的导数,降低了计算的复杂度!
本科生实验报告
实验课程数值计算方法
学院名称信息科学与技术学院
专业名称计算机科学与技术
学生
学生学号
指导教师
实验地点
实验成绩
二〇一六年五月二〇一六年五月
实验一
1.1
实验目的:掌握非线性方程求根的基本步骤及方法,。
实验容:试分别用二分法、简单迭代法、Newton迭代法、弦截法(割线法、双点弦法),求x5-3x3+x-1= 0在区间[-8,8]上的全部实根,误差限为10-6。
returnx1-(f(x1)/(f(x1)-f(x0)))*(x1-x0);
}
//双点弦法迭代
doubletwopointchord(doublex0,doublex1){
doublex3=twopointchord_f(x0,x1);
cout<<x3<<endl;
while(fabs(f(x3))>precision){
cout<<"f(x3)"<<f(x3)<<endl;//输出x3的函数值
x0=x1;
x1=x3;
x3=twopointchord_f(x0,x1);//没有到达精度要求继续迭代
// cout<<x3<<endl;
}
cout<<f(x3)<<endl;
returnx3;//返回最终结果
}
//测试
voidmain(){
x1=newtonitera(x0);//继续迭代
cout<<x1<<endl;
}
returnx1;//返回最终结果
}
//==================双点弦法迭代======================
//构造弦截法的迭代公式
doubletwopointchord_f(doublex0,doublex1){
k
xk
f(xk)
1
-1.5
0.03125
5
-1.50667
0.0784566
2
-1.66149
0.376502
6
-1.505
-0.010079
3
-1.47175
-1.56322
7
-1.50507
0.000440988
4
-1.492
0.186801
8
-1.50507
2.30387e-006
表4-1
区间[-1.2,-0.9]结果x=-1
//构造迭代公式
doublefitera(doublex){
doubleresult=0;
doublexx=3*pow(x,3)-x+1;
if(xx<=0){
xx=-xx;
returnpow(xx,1.0/5.0)*(-1);}
else
returnpow(xx,1.0/5.0);
}
//简单迭代
doubleitera(doublex0){
mid=(a+b)/2;
if(f(a)*f(mid)<=0)b=mid;//判断与端点函数值得符号
elsea=mid;
cout<<mid<<endl;
}
r[x_count++]=mid;
returnmid;//返回最终结果
}
//================简单迭代法=========================
2.计算x2=x1-f(x1)(x1-x0)/f(x1)-f(x0);
3.判断f(x2)是否满足精度要求,若没有则按照上述步骤继续迭代,否则输出x2.x2即为方程的近似解。
第
测试结果
函数图像
函数Y=x5-3x3+x-1
二分法
[-1.6,-1.3]
k
xk
k
xk
k
xk
0
-1.45
5
-1.50156
10
-1.50493
4.输出x1,即为方程的近似解。
2.3 Newton迭代法
思想:设r是 的根,选取 作为r的初始近似值,过点 做曲线 的切线L,L的方程为 ,求出L与x轴交点的横坐标 ,称x1为r的一次近似值。过点 做曲线
的切线,并求该切线与x轴交点的横坐标 ,称 为r的二次近似值。重复以上过程,得r的近似值序列,其中, 称为r的
14
1.69029
1
1.725
8
1.69043
15
1.69029
2
1.6875
9
1.69014
16
1.69029
3
1.70625
10
1.69028
17
1.69028
4
1.69687
11
1.69036
18
1.69028
5
1.69219
12
1.69032
6
1.68984
13
1.6903
表1-3
简单
初值-1.5
intm=0;//根的个数
intx_count;
doubleprecision=0.000001;//精度要求
//函数的表达式(x^5-3x^3+x-1)
doublef(doublex){
return(pow(x,5)-3*pow(x,3)+x-1);
}
voidinit(){//根据函数图像确定根的区间和迭代初值
-1.00005
1
-0.975
6
-1.00078
11
-0.999976
2
-1.0125
7
-0.999609
12
-1.00001
3
-0.99375
8
-1.0002
13
-0.999994
4
-1.00312
9
-0.999902
14
-1
表1-2
区间[1.5,1.8]
k
xk
k
xk
k
xk
0
1.65
7
1.69102
r[0]=-1.5;
r[1]=-1;
r[2]=1.6;
rn[0]=-1.6;
rn[1]=-1.2;
rn[2]=1.5;
}
//寻找根的区间
voidsearch(){//若没有给出区间和初值,进行逐步搜索有根区间
for(inti=0;i*foot-8<8;i++){
if(f(i*foot-8)*f((i+1)*foot-8)<0){
init();//初始化区间和迭代初值
/*测试代码输出每次的迭代结果和最终结果
cout<<"------------------------二分法----------------------"<<endl;
for(int i =0;i<3;i++){
double result=0;
cout<<"有根区间为["<<rn[i]<<" "<<rn[i]+foot<<"]"<<endl;
rn[m]=i*foot-8;
m++;
}
}
}
//=====================二分法==========================
doubleDichotomy(doublea,doubleb){
doublemid=0;
inti=0;
while(fabs(b-a)>precision){
1
-1.525
6
-1.50391
11
-1.505
2
-1.4875
7
-1.50508
12
-1.50504
3
-1.50625
8
-1.50449
13
-1.50506
4
-1.49688
9
-1.50479
14
#include<iostream>
#include<math.h>
usingnamespacestd;
doublefoot=0.3;//定义寻根步长
inta=-8,b=8;
double*rn=newdouble[5];//解的区间
double*r=newdouble[5];//方程近似解
18
1.69027
5
1.68278
12
1.69006
19
1.69028
6
1.68573
13
1.69015
20
1.69028
7
1.68753
14
1.6902
表2-3
牛顿
初值-1.5结果x=-1.50507
k
xk
k
xk
1
-1.5
4
-1.50504
2
-1.50471
5
-1.505063Βιβλιοθήκη -1.504976
-1.50507
表3-1
初值-1结果x=-1.50507
k
x
1
-1
2
-1
表3-2
初值1.6结果x=1.69028
k
xk
k
xk
1
1.6
5
1.69024
2
1.68602
6
1.69027
3
1.68893
7
1.69028
4
1.68985
8
1.69028
表3-3
双点
区间[-1.6,-1.3]结果x=-1.50507
k
xk
f(xk)
3并重复上述步骤,直达达到精度要求,则mid为方程的近似解。
2.2 简单迭代法
思想:迭代法是一种逐次逼近的方法,它是固定公式反复校正跟的近似值,使之逐步精确,最后得到精度要求的结果。
步骤:1.构造迭代公式f(x),迭代公式必须是收敛的。
2.计算x1,x1=f(x0).
3.判断|x1-x0|是否满足精度要求,如不满足则重复上述步骤。
//计算函数的一阶导数fderivatives(double x)
doublefderivatives(doublex){
return5*pow(x,4)-9*(x,2)+1;
}
//构造牛顿迭代公式newtonitera(double x)
doublenewtonitera(doublex){
if(fderivatives(x)==0)return-1;//若导数为0则停止迭代
12
-1.50489
18
-1.50505
表2-1
初值-1
k
x
1
-1
2
-1
表2-2
初值1.6结果x=1.69028
k
xk
k
xk
k
xk
1
1.6
8
1.68862
15
1.69023
2
1.65669
9
1.68927
16
1.69025
3
1.66987
10
1.68967
17
1.69027
4
1.6779
11
1.68991
k
xk
f(xk)
1
-1.01393
0.0415678
2
-1.0002
0.000607777
3
-0.999999
-3.11969e-006
4
-1
2.11001e-010
表4-2
区间[1.5,1.8]结果x=1.69028
k
xk
f(xk)
1
1.64403
-0.676455
2
1.68071
-0.151106
k
xk
k
xk
k
xk
1
-1.5
7
-1.50435
13
-1.50493
2
-1.50217
8
-1.50453
14
-1.50497
3
-1.50287
9
-1.50466
15
1.50499
4
-1.50341
10
-1.50476
16
-1.50501
5
-1.50381
11
-1.50483
17
-1.50504
6
-1.50412
cout<<x0<<endl;
doublex1=fitera(x0);
while(fabs(x1-x0)>precision){
x0=x1;
x1=fitera(x0);//没有到达精度要求继续迭代
cout<<x1<<endl;
}
returnx1;//返回最终结果
}
//===============牛顿迭代法==================
double result=0;
cout<<"有根区间为["<<rn[i]<<" "<<rn[i]+foot<<"]"<<endl;
double x0 =r[i]; //取得初值
result=itera(x0); //带入公式
cout<<"求得近似解为"<<result<<endl;
else
returnx-(f(x)/fderivatives(x));
}
//牛顿迭代
doublenewton(doublex0){
doublex1=newtonitera(x0);
while(fabs(x1-x0)>precision){
x0=x1;
if(newtonitera(x0)==-1)break;
要求:讨论求解的全过程,对所用算法的局部收敛性,优缺点等作分析及比较,
第
2.1二分法
思想:在函数的单调有根区间,将有根区间不断的二分,寻找方程的解。
步骤:1.取中点mid=(x0+x1)/2
2.若f(mid)=0,则mid为方程的根,否则比较与两端的符号,若与f(x0)
异号,则根在[x0,mid]之间,否则在[mid,x1]之间。
3
1.69126
0.0157988
4
1.69027
-0.000313515
5
1.69028
-6.3006e-007
表4-3
从测试结果可以看出二分法和简单迭代法的收敛速度远大于牛顿迭代和弦截法的收敛速度。二分法和简单迭代法的公式易于构造和计算,牛顿迭代法虽然收敛高,但要求导数,计算的复杂度高!双点弦法随稍慢于牛顿跌代法,可以用差商代替牛顿迭代法中的导数,降低了计算的复杂度!
本科生实验报告
实验课程数值计算方法
学院名称信息科学与技术学院
专业名称计算机科学与技术
学生
学生学号
指导教师
实验地点
实验成绩
二〇一六年五月二〇一六年五月
实验一
1.1
实验目的:掌握非线性方程求根的基本步骤及方法,。
实验容:试分别用二分法、简单迭代法、Newton迭代法、弦截法(割线法、双点弦法),求x5-3x3+x-1= 0在区间[-8,8]上的全部实根,误差限为10-6。
returnx1-(f(x1)/(f(x1)-f(x0)))*(x1-x0);
}
//双点弦法迭代
doubletwopointchord(doublex0,doublex1){
doublex3=twopointchord_f(x0,x1);
cout<<x3<<endl;
while(fabs(f(x3))>precision){
cout<<"f(x3)"<<f(x3)<<endl;//输出x3的函数值
x0=x1;
x1=x3;
x3=twopointchord_f(x0,x1);//没有到达精度要求继续迭代
// cout<<x3<<endl;
}
cout<<f(x3)<<endl;
returnx3;//返回最终结果
}
//测试
voidmain(){
x1=newtonitera(x0);//继续迭代
cout<<x1<<endl;
}
returnx1;//返回最终结果
}
//==================双点弦法迭代======================
//构造弦截法的迭代公式
doubletwopointchord_f(doublex0,doublex1){
k
xk
f(xk)
1
-1.5
0.03125
5
-1.50667
0.0784566
2
-1.66149
0.376502
6
-1.505
-0.010079
3
-1.47175
-1.56322
7
-1.50507
0.000440988
4
-1.492
0.186801
8
-1.50507
2.30387e-006
表4-1
区间[-1.2,-0.9]结果x=-1
//构造迭代公式
doublefitera(doublex){
doubleresult=0;
doublexx=3*pow(x,3)-x+1;
if(xx<=0){
xx=-xx;
returnpow(xx,1.0/5.0)*(-1);}
else
returnpow(xx,1.0/5.0);
}
//简单迭代
doubleitera(doublex0){
mid=(a+b)/2;
if(f(a)*f(mid)<=0)b=mid;//判断与端点函数值得符号
elsea=mid;
cout<<mid<<endl;
}
r[x_count++]=mid;
returnmid;//返回最终结果
}
//================简单迭代法=========================
2.计算x2=x1-f(x1)(x1-x0)/f(x1)-f(x0);
3.判断f(x2)是否满足精度要求,若没有则按照上述步骤继续迭代,否则输出x2.x2即为方程的近似解。
第
测试结果
函数图像
函数Y=x5-3x3+x-1
二分法
[-1.6,-1.3]
k
xk
k
xk
k
xk
0
-1.45
5
-1.50156
10
-1.50493
4.输出x1,即为方程的近似解。
2.3 Newton迭代法
思想:设r是 的根,选取 作为r的初始近似值,过点 做曲线 的切线L,L的方程为 ,求出L与x轴交点的横坐标 ,称x1为r的一次近似值。过点 做曲线
的切线,并求该切线与x轴交点的横坐标 ,称 为r的二次近似值。重复以上过程,得r的近似值序列,其中, 称为r的
14
1.69029
1
1.725
8
1.69043
15
1.69029
2
1.6875
9
1.69014
16
1.69029
3
1.70625
10
1.69028
17
1.69028
4
1.69687
11
1.69036
18
1.69028
5
1.69219
12
1.69032
6
1.68984
13
1.6903
表1-3
简单
初值-1.5
intm=0;//根的个数
intx_count;
doubleprecision=0.000001;//精度要求
//函数的表达式(x^5-3x^3+x-1)
doublef(doublex){
return(pow(x,5)-3*pow(x,3)+x-1);
}
voidinit(){//根据函数图像确定根的区间和迭代初值
-1.00005
1
-0.975
6
-1.00078
11
-0.999976
2
-1.0125
7
-0.999609
12
-1.00001
3
-0.99375
8
-1.0002
13
-0.999994
4
-1.00312
9
-0.999902
14
-1
表1-2
区间[1.5,1.8]
k
xk
k
xk
k
xk
0
1.65
7
1.69102
r[0]=-1.5;
r[1]=-1;
r[2]=1.6;
rn[0]=-1.6;
rn[1]=-1.2;
rn[2]=1.5;
}
//寻找根的区间
voidsearch(){//若没有给出区间和初值,进行逐步搜索有根区间
for(inti=0;i*foot-8<8;i++){
if(f(i*foot-8)*f((i+1)*foot-8)<0){
init();//初始化区间和迭代初值
/*测试代码输出每次的迭代结果和最终结果
cout<<"------------------------二分法----------------------"<<endl;
for(int i =0;i<3;i++){
double result=0;
cout<<"有根区间为["<<rn[i]<<" "<<rn[i]+foot<<"]"<<endl;
rn[m]=i*foot-8;
m++;
}
}
}
//=====================二分法==========================
doubleDichotomy(doublea,doubleb){
doublemid=0;
inti=0;
while(fabs(b-a)>precision){
1
-1.525
6
-1.50391
11
-1.505
2
-1.4875
7
-1.50508
12
-1.50504
3
-1.50625
8
-1.50449
13
-1.50506
4
-1.49688
9
-1.50479
14