引言
若函数在 f(x) 在区间 [a,b] 上连续,且原函数为 F(x),则有 Newton-Leibniz 公式 ∫abf(x)dx=F(b)−F(a)。在实际情况中,f(x) 的原函数往往过于复杂甚至难以求解,我们不得不用数值积分的方式得到定积分的近似解。
数值积分就是对于 f(x),选择合适的离散点 a≤x0<x1<⋯<xn≤b,并给离散点的函数值 f(xk) 合适的权值 Ak,从而构造出近似解: ∫abf(x)dx≈k=0∑nAkf(xk)。记 I(f)=∫abf(x)dx,Q(f)=k=0∑nAkf(xk),则截断误差(余项)R(f)=I(f)−Q(f)。
数值积分方法
Newton-Cotes 求积公式
选择 n+1 个离散点 a≤x0<x1<⋯<xn≤b,用 Lagrange 插值多项式近似表示 f(x),则 Q(f)=∫ab[k=0∑nlk(x)f(xk)]dx=k=0∑n[∫ablk(x)dx]f(xk),其中 Ak=∫ablk(x)dx。截断误差 E(f)=I(f)−Q(f)=∫ab[f(x)−k=0∑nlk(x)f(xk)]dx=∫ab(n+1)!f(n+1)(ξ)ωn+1dx。
令 x0∼xn 等距分布,根据采样点数量 n+1 的不同,依次对应不同的求积公式。
代数精度
若对任一不超过 m 次的多项式 pm(x),Newton-Cotes 求积公式总有 I(pm)=Q(pm),而对某一个 m+1 次多项式 pm+1(x),I(pm+1)=Q(pm+1),则称此求积公式的代数精度为 m。
要验证求积公式的代数精度为 m,只需要验证对于 f(x)=1,x,⋯,xm,I(f)=Q(f) 成立,对于 f(x)=xm+1,I(f)=Q(f)。
有结论:n 次插值型求积公式的代数精度至少为 n 次;反之,如果求积公式 ∫abf(x)dx≈k=0∑nAkf(xk) 的代数精度至少为 n 次,则它必定是插值型的。
梯形求积公式
取 n=1,则 x0=a,x1=b,求积公式为 Q(f)=2b−a[f(a)+f(b)],实际上就是用梯形面积代替积分。余项 E1=2!f′′(ξ)∫ab(x−a)(x−b)dx=−121f′′(η)(b−a)3,η∈(a,b)。
Simpson 求积公式
取 n=2,求积公式 Q(f)=6b−a[f(a)+4f(2a+b)+f(b)]。
Simpson 83 求积公式
取 n=3,求积公式 Q(f)=8b−a[f(a)+3f(32a+b)+3f(3a+2b)+f(b)]。
Cotes 求积公式
取 n=4,求积公式 Q(f)=90b−a[7f(a)+32f(43a+b)+12f(2a+b)+32f(4a+3b)+7f(b)]。
复化求积公式
随着选取的离散点的个数增多,Newton-Cotes 公式的精度也会越高。但是对于 n≥7 时的 Newton-Cotes 公式,它的各项系数开始出现负值。根据误差理论的研究,当积分公式开始出现负值时,可能导致舍入误差较大,因此通过增加求积节点数来提高计算精度并不是一种好方法。
不妨将积分区间划分成若干个小区间,在每个小区间上应用低次 Newton-Cotes 公式,然后把所有小区间上的计算结果累加得到整个区间上的积分。
复化梯形公式
将 [a,b] 分成 n 等分,其中节点 xi=a+ih,h=nb−a (i=0,1,⋯,n)。
I=∫abf(x)dx=k=0∑n−1∫xkxk+1f(x)dx≈k=0∑n−12h[f(xk)+f(xk+1)]=2h[f(a)+k=1∑n−1f(xk)+f(b)],即 Tn=2h[f(a)+k=1∑n−1f(xk)+f(b)]。余项 Rn(f)=−12b−ah2f′′(η),η∈(a,b)。
复化Simpson公式
推导过程与复化梯形公式类似,Sn=6h[f(a)+4k=0∑n−1f(xk+21)+2k=1∑n−1f(xk)+f(b)]。
步长 h 的选取
通常采取将区间不断对分的方法,即 n=2k;反复使用复化求积公式,直到相邻两次计算结果之差的绝对值小于指定精度 ε。
以复化梯形公式举例,首先将 [a,b] 分成 n 等分,步长为 h=nb−a。$\displaystyle T_n=\sum\limits_{k=0}^{n-1} \frac{h}{2}\left[f(x_k)+f(x_{k+1})\right]=\frac{h}{2}\left[f(a)+\sum\limits_{k=1}^{n-1}f(x_k)+f(b)\right]$,$\displaystyle T_{2n}=\sum\limits_{k=0}^{n-1}\frac{h}{4}\left\{\left[f(x_k)+f(x_{k+\frac{1}{2}})\right]+\left[f(x_{k+\frac{1}{2}})+f(x_{k+1})\right]\right\}=\frac{h}{4}\sum\limits_{k=0}^{n-1}\left[f(x_k)+f(x_{k+\frac{1}{2}})\right]+\frac{h}{2}\sum\limits_{k=0}^{n-1}f(x_{k+\frac{1}{2}})=\frac{1}{2}T_n+\frac{h}{2}\sum\limits_{k=0}^{n-1}f(x_{k+\frac{1}{2}})$。
由复化梯形公式的余项知,I−Tn=−12b−ah2f′′(η1),I−T2n=−12b−a(2h)2f′′(η2);假设 f′′(x) 变化不大,即 f′′(η1)≈f′′(η2),得到 I−T2nI−Tn≈4,即 I≈T2n+31(T2n−Tn)。当 T2n−Tn<ε,有 I−T2n<3ε,因此不断将区间对分的方法是可行的。
Romberg 求积公式
在上面的推导中,I≈T2n+31(T2n−Tn),可认为 T=T2n+31(T2n−Tn) 是一个较 T2n 更精确的值。实际上,将 T2n 用 Tn 表示,再将 Tn 展开,可以得到 Sn=T;即 Sn=34T2n−31Tn,类似的有 Cn=1516S2n−161Sn,Rn=6364C2n−631Cn。
称 Rn 为 Romberg 公式,用 Romberg 方法求数值积分类似填表的过程。
梯形序列 |
Simpson序列 |
Cotes序列 |
Romberg序列 |
T1 |
|
|
|
T2 |
S1 |
|
|
T4 |
S2 |
C1 |
|
T8 |
S4 |
C2 |
R1 |
T16 |
S8 |
C4 |
R2 |
用 I=∫ab1+x24dx 且 ε=10−4 举例,Romberg 方法的代码实现如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| #include<iostream> #include<cmath> using namespace std; double ans[20][4]; inline double f(double x) { return 4.0 / (1 + x * x); } int main() { double a, b; cin >> a >> b; double h = b - a; int n = 1; ans[0][0] = (f(a) + f(b)) * h / 2.0; printf("%.15lf\n", ans[0][0]); for (int i = 1;;i++) { ans[i][0] = 0.5 * ans[i - 1][0]; for (int k = 0;k <= n - 1;k++) { ans[i][0] += h * 0.5 * f((a + k * h + a + (k + 1) * h) / 2.0); } n <<= 1; h = (b - a) / (double)n; printf("%.15lf ", ans[i][0]); if (i >= 1) { ans[i][1] = ans[i][0] * 4 / 3.0 - 1.0 / 3.0 * ans[i - 1][0]; printf("%.15lf ", ans[i][1]); } if (i >= 2) { ans[i][2] = ans[i][1] * 16 / 15.0 - 1.0 / 15.0 * ans[i - 1][1]; printf("%.15lf ", ans[i][2]); } if (i >= 3) { ans[i][3] = ans[i][2] * 64 / 63.0 - 1.0 / 63.0 * ans[i - 1][2]; printf("%.15lf", ans[i][3]); } if (i >= 4) { if (fabs(ans[i][3] - ans[i - 1][3]) < 0.0001) { return 0; } } putchar('\n'); } return 0; }
|