梯形积分
设f(x)在[a,b]上连续,若要计算其积分,则
∫
a
b
f
(
x
)
d
x
=
F
(
b
)
−
F
(
a
)
\int_a^b f(x)dx = F(b) - F(a)
∫abf(x)dx=F(b)−F(a)
其中F(x)为f(x)的原函数,但是计算机直接计算出该积分函数比较困难,因此需要近似求解。梯形积分使用函数的区间边界点作梯形进行计算,即
∫
a
b
f
(
x
)
d
x
≈
(
f
(
a
)
+
f
(
b
)
)
(
b
−
a
)
2
\int_a^b f(x)dx \approx \frac{(f(a)+f(b))(b-a)}{2}
∫abf(x)dx≈2(f(a)+f(b))(b−a)
当[a,b]区间比较小时,这个误差就比较小,对于[a,b]区间比较大的情况,普通的梯形积分就不再适用,需要对梯形积分进行复化。
复化梯形积分
复化梯形积分就是在区间[a,b]上进行m次划分,每次划分得到n个子区间,然后计算每个子区间的梯形积分,最后将这m个梯形积分相加,得到整个区间的梯形积分。
假设[a,b]区间被划分为n个区间,h=(b-a)/n,
x
k
=
a
+
k
h
(
k
=
0
,
⋯
,
n
)
x_k=a+kh(k=0,\cdots ,n)
xk=a+kh(k=0,⋯,n)
∫
a
b
f
(
x
)
d
x
≈
∑
k
=
1
n
h
2
[
f
(
x
k
−
1
+
f
(
x
k
)
)
]
=
h
2
[
f
(
a
)
+
2
∑
k
=
1
n
−
1
f
(
x
k
)
+
f
(
b
)
]
\int_a^b f(x)dx \approx \sum_{k=1}^n \frac{h}{2}[f(x_{k-1}+f(x_k))]\\ =\frac{h}{2}[f(a)+2\sum_{k=1}^{n-1}f(x_k)+f(b)]
∫abf(x)dx≈k=1∑n2h[f(xk−1+f(xk))]=2h[f(a)+2k=1∑n−1f(xk)+f(b)]
误差分析
复化梯形积分要划分为多少个区间才合适呢?显然需要做一个误差控制,但是问题就在于如何判断复化梯形积分与实际积分值的误差,使用梯形积分的原因就是因为原本的积分不容易求出来,所以直接比较是不可以的,此处需要使用到事后误差分析,即区间继续增加划分数量时,积分值变化小于某个值时即可认为此时的积分与实际的误差小于一定范围。
复化梯形积分的余项可以表示为:
R
[
f
]
=
∑
k
=
1
n
[
−
h
3
12
f
′
′
(
ξ
k
)
]
=
−
h
2
12
(
b
−
a
)
∑
k
=
1
n
f
′
′
(
ξ
k
)
n
=
−
h
2
12
(
b
−
a
)
f
′
′
(
ξ
)
(
ξ
∈
(
a
,
b
)
)
=
−
(
b
−
a
)
3
12
n
2
f
′
′
(
ξ
)
(
ξ
∈
[
a
,
b
]
)
R[f]=\sum_{k=1}^n [-\frac{h^3}{12}f''(\xi_k)]\\ =-\frac{h^2}{12}(b-a)\frac{\sum_{k=1}^n f''(\xi_k)}{n}\\ =-\frac{h^2}{12}(b-a)f''(\xi)(\xi \in (a,b))\\ =-\frac{(b-a)^3}{12n^2}f''(\xi)(\xi \in [a,b])
R[f]=k=1∑n[−12h3f′′(ξk)]=−12h2(b−a)n∑k=1nf′′(ξk)=−12h2(b−a)f′′(ξ)(ξ∈(a,b))=−12n2(b−a)3f′′(ξ)(ξ∈[a,b])
因此,要求梯形积分与实际积分值小于
ϵ
\epsilon
ϵ,则其余项小于
ϵ
\epsilon
ϵ:
I
(
f
)
−
T
n
(
f
)
=
−
b
−
a
12
h
2
f
′
′
(
ξ
)
I
(
f
)
−
T
2
n
(
f
)
=
−
b
−
a
12
(
h
/
2
)
2
f
′
′
(
η
)
I(f)-T_n(f)=-\frac{b-a}{12}h^2f''(\xi)\\ I(f)-T_{2n}(f)=-\frac{b-a}{12}(h/2)^2f''(\eta)
I(f)−Tn(f)=−12b−ah2f′′(ξ)I(f)−T2n(f)=−12b−a(h/2)2f′′(η)
两者可以近似为:
I
(
f
)
−
T
n
(
f
)
≈
4
[
I
(
f
)
−
T
2
n
(
f
)
]
I(f)-T_n(f)\approx 4[I(f)-T_{2n}(f)]\\
I(f)−Tn(f)≈4[I(f)−T2n(f)]
因此若有
T
2
n
(
f
)
−
T
n
(
f
)
<
3
ϵ
T_{2n}(f)-T_n(f)< 3\epsilon
T2n(f)−Tn(f)<3ϵ
即可等价为
I
(
f
)
−
T
2
n
(
f
)
<
ϵ
I(f)-T_{2n}(f)< \epsilon
I(f)−T2n(f)<ϵ
代码实现
#include<iostream>
#include<cmath>
#include<iomanip>//这个头文件仅仅是用来设置cout的输出精度
#define abs(x) (x>0?x:-x)
using namespace std;
//梯形积分,传入参数为分段的n,积分下限a,积分上限b,对应的积分函数
double trapezium(int n,double a,double b,float(*f)(float x))
{
double f_x=0.0f;
double h=(b-a)/n;
for (int i = 1; i < n; i++)
{
f_x+=f(a+i*h);//梯形公式的f(x_k)的累加和
}
f_x*=h;
f_x+=(f(a)+f(b))*h/2;//根据n算出对应的复化梯形积分
return f_x;
}
//直接在这里换函数,函数为sin(x)/x
float fx(float x)
{
float result;
float x_temp=((x==0)?1e-15:x);
result=sin(x_temp)/x_temp;
return result;
}
int main()
{
double error=1e-6;//表示误差小于10^-6次方
double a=0.0,b=2.0;//积分上下限
int n=1;
double f_x_n=(fx(a)+fx(b))*(b-a)/2;
double f_x_2n;
//可以在此处添加循环次数控制,防止误差无法缩小的情况出现
while(true)
{
f_x_2n=trapezium(n*2,a,b,fx);//算T2n
if(fabs(f_x_n-f_x_2n)<(error*3))
{
//cout<<n<<":trapezium error="<<fabs(f_x_n-f_x_2n)<<endl;
cout << "梯形积分的误差为:" << fabs(f_x_n - f_x_2n) << endl;
n*=2;
break;
}
n+=1;
f_x_n=trapezium(n,a,b,fx);//算Tn
}
cout<<"区间划分数量:n="<<n<<",积分值为:"<<std::setprecision(10)<<f_x_2n<<endl;
return 0;
}
结果分析
运行程序后,被积函数为sin(x)/x,积分区间为[0,2],为了达到
I
(
f
)
−
T
2
n
(
f
)
<
1
0
−
6
I(f)-T_{2n}(f)< 10^{-6}
I(f)−T2n(f)<10−6,需要将区间划分为382个小区间,此时采用事后误差估计法求得的
T
2
n
(
f
)
−
T
n
(
f
)
=
2.98242
×
1
0
−
6
T_{2n}(f)-T_n(f)=2.98242\times 10^{-6}
T2n(f)−Tn(f)=2.98242×10−6。
为了验证事后误差估计法,采用Matlab进行计算,
I
(
f
)
I(f)
I(f)如下:
计算
T
2
n
(
f
)
−
I
(
f
)
T_{2n}(f)-I(f)
T2n(f)−I(f)如下:
可以看出事后误差估计得到的结果符合期望。