数值计算 程序设计数值积分.docx
《数值计算 程序设计数值积分.docx》由会员分享,可在线阅读,更多相关《数值计算 程序设计数值积分.docx(16页珍藏版)》请在冰豆网上搜索。
![数值计算 程序设计数值积分.docx](https://file1.bdocx.com/fileroot1/2022-11/16/c123eee0-11c9-4e07-80ec-6d0a2e86e28a/c123eee0-11c9-4e07-80ec-6d0a2e86e28a1.gif)
数值计算程序设计数值积分
《数值方法》
课程设计
内容提要:
实际问题中常常需要计算积分,有些数值方法,如微分方程和积分方程的求解,也都和积分计算相联系。
依据微积分基本定理,对于积分
只要找到被积函数f(x)的原函数F(x)。
F’(x)=f(x),便有牛顿―莱布尼兹公式
来求得积分.但实际运用这种方法往往有困难,因为大量的被积函数,找不到用初等函数表示的原函数;另外当f(x)是由实验测量或数值计算给出的一张数据表时,牛顿―莱布尼兹公式也不能直接运用,因此,实际往往通过其他的一些方法如利用复化梯形公式、龙贝格公式、牛顿―莱布尼兹公式等来求解。
复化梯形求积法通常把积分区间等分成若干个子区间,在每一个子区间上用低阶的求积公式,对所有的子区间求和即得整个区间[a,b]上的积分公式。
龙贝格算法是在区间逐次分半过程中,对梯形公式的近似值进行加权平均获得准确程度较高的积分近似值的一种方法,它具有公式简练、计算结果准确、使用方便、稳定性好等优点,因此在等距情形宜采用龙贝格求积公式。
龙贝格算法也称为逐次分半加速法,它是在梯形公式、辛普森公式和牛顿―莱布尼兹公式之间的关系的基础上.构造出一种加速计算积分的方法。
作为一种外推算法,它在不增加计算量的前提下提高了误差的精度。
在等距基点的情况下,用计算机计算积分值通常都采用把区间逐次分半的方法进行。
这样,前一次分割得到的函数值在分半以后仍可被利用.并且易于编程。
目录
一、程序设计主要内容……………………………………………………3
1.程序设计目的…………………………………………………………3
2.程序设计背景…………………………………………………………3
3.程序设计要求…………………………………………………………3
4.程序设计意义…………………………………………………………4
5.所做工作:
……………………………………………………………4
二、理论分析…………………………………………………………………4
1、问题分析………………………………………………………………4
2、理论依据及求解对策…………………………………………………4
三、方法详解……………………………………………………………………5
1、推导…………………………………………………………………5
2.分析及程序框图……………………………………………………5
四、问题解决…………………………………………………………………9
五、结果分析………………………………………………………………13
六、体会……………………………………………………………………14
七、参考文献…………………………………………………………………14
一.程序设计主要内容
1.程序设计目的:
1)学会用数值积分避开求f(x)的原函F(x)的繁琐步骤,并可以有效的控制结果,使其在要求的误差范围之内。
2)在某些求积函数中,用数值积分求解一些原函数F(x)不能用初等函数表示成有限形式。
3)熟练掌握用复化梯形法和龙贝格法求解积分。
4)编程实现复化梯形法的递推算法。
5)编程实现龙贝格(Romberg)积分法。
2.程序设计背景:
对于较大积分区间、复杂被积函数、较高精度要求的数值积分问题,需要较多的求积节点。
如果采用高阶插值型求积公式,当被积函数f(x)不是多项式函数时,求积过程可能不稳定,因此这时只能采用复化求积。
而龙贝格求积是对逐次分半梯形公式求积公式加速的一种外推方法,收敛速度较复化求积更快,也是一种实用的数值积分方法。
在一元函数的积分学中,我们已经熟知,若函数f(x)在区间[a,b]上连续且其原?
函数为F(x),则可用牛顿―莱布尼兹公式来求定积分。
牛顿―莱布尼兹公式虽然在理论上或在解决实际问题中都起了很大的作用,?
但它并不能完全解决定积分的计算问题。
因为定积分的计算常常会碰到以下三种情况:
(1)被积函数f(x)的原函数F(x)不易找到。
许多很简单的函?
数,例
等,其原函数都不能用初等函数表示成有限形式。
(2)被积函数f(x)没有具体的解析表达式。
其函数关系由表格或图形表示,无法求出原函数。
(3)尽管f(x)的原函数能表示成有限形式但其表达式相当复杂。
另外,许多实际问题中的被积函数往往是列表函数或其他形式的非连续函数,对这类函数的定积分,也不能用不定积分方法求解。
由于以上原因,数值积分的理论与方法一直是计算数学研究的基本课题。
3.程序设计要求:
1)用复化梯形法的递推算法计算不同积分,要求误差不超过10-10,并输出积分区间的分割数。
2)用Romberg积分法计算不同积分,要求误差不超过10-10,并与Simpson方法比较计算量。
4.程序设计意义:
数值计算的广泛性和深入性已成为现代科技发展的重要特征,数值计算和理
论研究、科学实验并列为科学研究的三大支柱。
用数学方法、将计算机作为工具、提高解决各种实际问题的能力是现代社会的需要,也是知识更新的必要环节。
数值积分方法作为数值计算方法中的一个重要部分,如果将其与c++等语言中程序设计相结合。
用正确的数值计算方法编写相应的c++程序。
我们就能很好地解决一些复杂的实际问题,做到既有速度又有精度。
5.所做工作:
用VC++编程实现复化梯形法的递推算法和龙贝格(Romberg)积分法,并控制了结果的精度,比较辛普森和龙贝格积分的计算量,使其在要求的误差范围之内。
二、理论分析:
1、问题分析:
因原问题要求误差不超过10-10,需把积分区间[a,b]分成若干个小区间,使被积函数f(x)在每一个小区间内足够平滑,然后用低阶数值积分公式求f(x)在每一个小区间内的积分,再对所有小区间的积分结果求和,就得到了f(x)在[a,b]上的积分。
2、理论依据及求解对策:
1)把积分区间[a,b]等分为m个小区间,令步长h=
,求积节
i=0,,1,2…m,等距节点复化梯形公式为
它的余项函数为
2)用Tm表示把[a,b]作m等分并按复合梯形公式求积的结果,将每一小段再对分,令新的小段的长h′=h/2,则T2m与Tm之间有如下关系:
其中
三、方法详解:
1、推导:
1)用梯形公式求f(x)在每个小区间上积分余项之和:
2)等距节点复化梯形公式的余项为每个小子区间上积分余项之和:
3)设
中最小的1项为
最大的1项为
。
由连续函数介值定理可知,在
之间至少存在1点
,使
。
又因为
所以
所以
2.分析及程序框图:
1)x为1时,函数值为1;否则返回函数f(x)
2)龙贝格中根据T1、T2和m计算下一个数并返回
3)龙贝格积分法求解过程
4)用复化梯形法的递推算法求解过程
5)辛普森积分法的求解过程分析:
在积分区间[
]上,根据给定的插值条件[
]、[
]和[
],构造一个二次插值求积多项式
,并以
的积分值近似的代替
。
从几何角度而言,是用过三点的抛物线面积近似的代替积分的曲边面积,如图:
流程图:
四、问题解决:
程序代码:
1)下面为复化梯形和龙贝格的程序及运行结果
//sin(x)/x:
#include
#include
#defineeps1e-10
doublefun(doublex);
doubleRomberge(doublea,doubleb);
//函数Tm()为T-数表的计算公式
doubleTm(doubleT1,doubleT2,intm);
doublefun(doublex)
{
if(x==0)
return1;
//x为1时,函数值为1
return(sin(x)/x);
//返回被积函数的值
}
doubleTm(doubleT1,doubleT2,intm)
{
//根据T1、T2和m计算下一个数并返回
return((pow(4,m)*T1-T2)/(pow(4,m)-1));
}
doubleRomberge(doublea,doubleb)
{
doubleT[10];
//用于存储T-数表第一行的数据
intI=1;
T[0]=(b-a)*(fun(a)+fun(b))/2;
doubleT1,T2;
intflag;//flag用于标记十分求的符合精度的值
do{
flag=0;
intn=int(pow(2,I-1));//n表示区间等分数
doubleh=(b-a)/n;
doubletemp=0;
for(inti=0;iT1=T[0]/2+h*temp/2;
//利用变步长提醒公式计算T-数表第(I+1)行的第一个数据
//将T-数表第I+1行的前I-1个数据存入数值
for(intm=1;m
{
T2=Tm(T1,T[m-1],m);
T[m-1]=T1;
T1=T2;
}
T2=Tm(T1,T[I-1],1);
//计算T-数表第(I+1)行的最后一个数据
if(fabs(T2-T[I-1])>eps)
//比较T-数表第(I+1)行和第i行的最后一个数据的差值
{
////将T-数表的第I+1行的最后两个数据存入数组
T[I-1]=T1;
T[I]=T2;
++I;
flag=1;//表示没有求得符合精度的值
}
}while(flag);
returnT2;//返回符合精度的解
}
doublebtrapeze(doublea,doubleb)
{
intn=1;
doubleh=b-a;
doublet1=h*(fun(a)+fun(b))/2;
doublet2=t1/2+h*fun(a+h/2)/2;
while(fabs(t2-t1)>eps)
{
n*=2;
h/=2;
t1=t2;
doubletemp=0;
for(inti=1;i<=n;++i)
temp+=fun(a+(i-1.0/2)*h);
t2=t1/2+h*temp/2;
}
returnt2;//返回步长h最合适时的定积分的近似值
}
intmain()
{
doublea,b,i,j;//a,b分别为积分的上限,下限,h为步长
a=0;
b=1;
i=Romberge(a,b);
printf("用龙贝格积分法计算sin(x)/x在0到1上的积分为:
\n");
printf("%.10f",i);
j=btrapeze(a,b);
printf("\n用复化梯形法计算sin(x)/x在0到1上的积分为:
\n");
printf("%.10f\n",j);
return0;
}
下面即为sin(x)/x在复化梯形公式和龙贝格积分的计算结果
下面即为cos(sin(x))在复化梯形公式和龙贝格积分的计算结果
2)下面为辛普森的程序及cos(sin(x))运行结果
#include
#include
#defineN16385
doublefunc(doublex)
{