自适应Simpson积分学习笔记

本文转载自洛谷日报微信版第35期,点击文末阅读原文查看原文。

问题引入:求曲边梯形面积

Simpson法的用途就在于求不规则多边形的面积。在这里,我们从曲边梯形说起。

举个例子:曲边梯形ABCD就是下图中曲线AB、线段ACCDDB围成的图形,我们想要求出它的面积 。

img

对于这个问题,在数学中,我们可以将这个多边形在竖直方向切成一条条细线,然后将面积累加,这也是微积分的重要思想。

但是在信息学中,我们无法做到这么精确的事情,于是,我们想办法用一些图形的面积累加求近似解。

利用矩形去近似面积

img

但是这个方法还是太粗糙了,于是我们考虑优化它——对于每一段,我们取端点中点在函数上的对应点,借助这个点来构造矩形。

img

方法实现:

C ( a , 0 ) C(a,0) C(a,0) D ( b , 0 ) D(b,0) D(b,0)。那么: ∫ a b f ( x ) d x ≈ Δ x i ∑ i = 1 n − 1 f ( ( i + 1 2 ) Δ x i ) \displaystyle\intop_a^bf(x)\mathrm{d}x\thickapprox\Delta x_i\sum_{i=1}^{n-1}{f((i+\frac{1}{2})\Delta x_i)} abf(x)dxΔxii=1n1f((i+21)Δxi)

为了方便,我们让每一段的长度相等,即对于每一段,有: Δ x = b − a n \Delta x=\frac{b-a}{n} Δx=nba

那么: ∫ a b f ( x ) d x ≈ Δ x ∑ i = 1 n − 1 f ( ( i + 1 2 ) Δ x ) \color{red}\displaystyle\intop_a^bf(x)\mathrm{d}x\thickapprox\Delta x\sum_{i=1}^{n-1}{f((i+\frac{1}{2})\Delta x)} abf(x)dxΔxi=1n1f((i+21)Δx)

利用梯形去近似面积

img

可以证明,这个方法和矩形近似的优化是一样的,不过这种方法的实现简单。

方法实现:

C ( a , 0 ) C(a,0) C(a,0) D ( b , 0 ) D(b,0) D(b,0)。那么: ∫ a b f ( x ) d x ≈ Δ x i ( ∑ i = 1 n − 1 f ( i Δ x i ) + f ( a ) + f ( b ) 2 ) \displaystyle\intop_a^bf(x)\mathrm{d}x\thickapprox\Delta x_i(\sum_{i=1}^{n-1}{f(i\Delta x_i)}+\frac{f(a)+f(b)}{2}) abf(x)dxΔxi(i=1n1f(iΔxi)+2f(a)+f(b))

为了方便,我们让每一段的长度相等,即对于每一段,有 Δ x = b − a n \Delta x=\frac{b-a}{n} Δx=nba

则有 ∫ a b f ( x ) d x ≈ Δ x ( ∑ i = 1 n − 1 f ( i Δ x ) + f ( a ) + f ( b ) 2 ) \color{red}\displaystyle\intop_a^bf(x)\mathrm{d}x\thickapprox\Delta x(\sum_{i=1}^{n-1}{f(i\Delta x)}+\frac{f(a)+f(b)}{2}) abf(x)dxΔx(i=1n1f(iΔx)+2f(a)+f(b))

利用抛物线去近似面积(Simpson法)

Simpson法是先将原曲线近似成一段段抛物线,然后再用牛顿-莱布尼茨公式求每一段的面积 。

img

可以看出,这个方法的效果相当好了。

我们来看看如何实现这种方法:设 C ( a , 0 ) C(a,0) C(a,0) D ( b , 0 ) D(b,0) D(b,0)

为了方便,我们让每一段的长度相等,即对于每一段,有 Δ x = b − a n \Delta x=\frac{b-a}{n} Δx=nba

对于每一段,我们如下处理:

设区间起点为 x 2 i − 2 x_{2i-2} x2i2,终点为 x 2 i x_{2i} x2i,中点为 x 2 i − 1 x_{2i-1} x2i1

我们要用过点 ( x 2 i − 2 , f ( x 2 i − 2 ) ) (x_{2i-2},f(x_{2i-2})) (x2i2,f(x2i2)) ( x 2 i − 1 , f ( x 2 i − 1 ) ) (x_{2i-1},f(x_{2i-1})) (x2i1,f(x2i1)) ( x 2 i , f ( x 2 i ) ) (x_{2i},f(x_{2i})) (x2i,f(x2i))的抛物线 g ( x ) = A x 2 + B x + C g(x)=Ax^2+Bx+C g(x)=Ax2+Bx+C来取代 f ( x ) f(x) f(x)

所以有:

f ( x 2 i − 2 ) = g ( x 2 i − 2 ) = A x 2 i − 2 2 + B x 2 i − 2 + C f(x_{2i-2})=g(x_{2i-2})=Ax_{2i-2}^2+Bx_{2i-2}+C f(x2i2)=g(x2i2)=Ax2i22+Bx2i2+C

f ( x 2 i − 1 ) = g ( x 2 i − 1 ) = A x 2 i − 1 2 + B x 2 i − 1 + C = A ( x 2 i − 2 + x 2 i 2 ) 2 + B ( x 2 i − 2 + x 2 i 2 ) + C f(x_{2i-1})=g(x_{2i-1})=Ax_{2i-1}^2+Bx_{2i-1}+C=A(\frac{x_{2i-2}+x_{2i}}{2})^2+B(\frac{x_{2i-2}+x_{2i}}{2})+C f(x2i1)=g(x2i1)=Ax2i12+Bx2i1+C=A(2x2i2+x2i)2+B(2x2i2+x2i)+C

f ( x 2 i ) = g ( x 2 i ) = A x 2 i 2 + B x 2 i + C f(x_{2i})=g(x_{2i})=Ax_{2i}^2+Bx_{2i}+C f(x2i)=g(x2i)=Ax2i2+Bx2i+C

于是 ∫ x 2 i − 2 x 2 i f ( x ) d x ≈ ∫ x 2 i − 2 x 2 i g ( x ) d x \displaystyle\intop_{x_{2i-2}}^{x_{2i}}f(x)\mathrm{d}x\thickapprox\intop_{x_{2i-2}}^{x_{2i}}g(x)\mathrm{d}x x2i2x2if(x)dxx2i2x2ig(x)dx

= ( A 3 x 3 + B 2 x 2 + C x ) ∣ x 2 i − 2 x 2 i \qquad\qquad\qquad\enspace=(\frac{A}{3}x^3+\frac{B}{2}x^2+Cx)\Big|_{x_{2i-2}}^{x_{2i}} =(3Ax3+2Bx2+Cx)x2i2x2i

= Δ x 3 [ f ( x 2 i − 2 ) + 4 f ( x 2 i − 1 ) + f ( x 2 i ) ] \qquad\qquad\qquad\enspace=\frac{\Delta x}{3}[f(x_{2i-2})+4f(x_{2i-1})+f(x_{2i})] =3Δx[f(x2i2)+4f(x2i1)+f(x2i)]

所以: ∫ a b f ( x ) d x ≈ Δ x 3 ∑ i = 0 2 n − 2 [ f ( x 2 i ) + 4 f ( x 2 i + 1 ) + f ( x 2 i + 2 ) ] \color{red}\displaystyle\intop_a^bf(x)\mathrm{d}x\thickapprox\frac{\Delta x}{3}\sum_{i=0}^{2n-2}[f(x_{2i})+4f(x_{2i+1})+f(x_{2i+2})] abf(x)dx3Δxi=02n2[f(x2i)+4f(x2i+1)+f(x2i+2)]

不过也有人认为Simpson法是 n = 1 n=1 n=1时的情形,即 ∫ a b f ( x ) d x ≈ b − a 6 [ f ( a ) + 4 f ( a + b 2 ) + f ( b ) ] \color{blue}\displaystyle\intop_a^bf(x)\mathrm{d}x\thickapprox\frac{b-a}{6}[f(a)+4f(\frac{a+b}{2})+f(b)] abf(x)dx6ba[f(a)+4f(2a+b)+f(b)]

下面把这种方法叫做三点Simpson法。

自适应Simpson

自适应Simpson法就是对Simpson法的一个优化。

对一段区间 [ a , b ] [a,b] [a,b],我们做如下操作。

  1. 取中点 m i d = a + b 2 mid=\frac{a+b}{2} mid=2a+b

  2. 分别对区间 [ a , b ] [a,b] [a,b]、区间 [ a , m i d ] [a,mid] [a,mid]、区间 [ m i d , b ] [mid,b] [mid,b]应用三点Simpson法,设得到的面积分别为 S 0 S_0 S0 S 1 S_1 S1 S 2 S_2 S2

  3. S 0 S_0 S0 S 1 + S 2 S_1+S_2 S1+S2差别不大,就认为区间 [ a , b ] [a,b] [a,b]面积的近似值已经求得,否则分别对区间 [ a , m i d ] [a,mid] [a,mid]、区间 [ m i d , b ] [mid,b] [mid,b]递归应用本操作。

可以看出这个方法在保证了精度的同时保证了效率。

我们注意到,上述操作中有两个地方含糊不清。

一个是如何确定“差别不大”,一个是面积的近似值已经求得后返回的面积是多少。

我们认为当且仅当 ∣ S 1 + S 2 − S 0 ∣ &lt; 15 ϵ |S_1+S_2-S_0|&lt;15\epsilon S1+S2S0<15ϵ S 0 S_0 S0 S 1 + S 2 S_1+S_2 S1+S2差别不大(乘以 15 15 15这里可以按需调整)。

返回的面积则是 S 1 + S 2 + S 1 + S 2 − S 0 15 \color{blue}S_1+S_2+\frac{S_1+S_2-S_0}{15} S1+S2+15S1+S2S0

参考代码

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;

inline double fun(double x) {//函数带入求值 
    return x*x*x-2*x*x-x+3;
}

inline double sps(double l,double r) {//辛普森积分 
    double mid=(l+r)/2;
    return (fun(l)+4*fun(mid)+fun(r))*(r-l)/6.0;
}

double asr(double l,double r,double eps,double s) {//自适应辛普森积分 
    double mid=(l+r)/2;
    double ls=sps(l,mid);
    double rs=sps(mid,r);
    if (fabs(ls+rs-s)<=(eps*15)) {
        return ls+rs+(ls+rs-s)/15.0;
    }
    return asr(l,mid,eps/2,ls)+asr(mid,r,eps/2,rs);
}

int main() {
    double l,r;
    scanf("%lf%lf",&l,&r);
    printf("%lf",asr(l,r,1e-8,sps(l,r)));
    return 0;
}

经典例题

例1.[LG4525]【模板】自适应辛普森法1

计算积分: ∫ L R c x + d a x + b d x \displaystyle\intop_L^R\frac{cx+d}{ax+b}\mathrm{d}x LRax+bcx+ddx结果保留至小数点后6位。

数据保证计算过程中分母不为0且积分能够收敛。

[Analysis]

直接套模板就好了。

参考代码:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;

double a,b,c,d;

inline double fun(double x) {//函数带入求值 
    return (c*x+d)/(a*x+b);
}

inline double sps(double l,double r) {//辛普森积分 
    double mid=(l+r)/2;
    return (fun(l)+4*fun(mid)+fun(r))*(r-l)/6;
}

double asr(double l,double r,double eps,double s) {//自适应辛普森积分 
    double mid=(l+r)/2;
    double ls=sps(l,mid);
    double rs=sps(mid,r);
    if (fabs(ls+rs-s)<=eps*15) {
        return ls+rs+(ls+rs-s)/15;
    }
    return asr(l,mid,eps/2,ls)+asr(mid,r,eps/2,rs);
}

int main() {
    double l,r;
    scanf("%lf%lf%lf%lf%lf%lf",&a,&b,&c,&d,&l,&r);
    printf("%.6lf",asr(l,r,1e-8,sps(l,r)));
    return 0;
}
例2.[LG4526]【模板】自适应辛普森法2

计算积分 ∫ 0 ∞ x a x − x d x \displaystyle\intop_0^\infty x^{\frac{a}{x}-x}\mathrm{d}x 0xxaxdx

保留至小数点后5位。若积分发散,请输出orz

[Analysis]

这道题的式子看上去有些复杂,尤其是那个无穷大让人很头疼。对于这一类题目,我们可以试着画画函数图像,寻找一下规律。

img

通过图像,我们可以发现一下规律:

  • a &lt; 0 a&lt;0 a<0时,函数是发散的,直接输出orz即可。
  • a &gt; 0 , x &gt; 10 a&gt;0,x&gt;10 a>0x>10时,函数值就趋近于0了,于是我们只用考虑 x ∈ ( 0 , 10 ] \color{blue}x\in (0,10] x(0,10]的情况了__(注意 x ! = 0 \color{red}x!=0 x!=0)__。
  • 又因为本题对精度要求较高,要讲右边界改成20才能过。

参考代码:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;

double a;

inline double fun(double x) {//函数带入求值 
    return pow(x,a/x-x);
}

inline double sps(double l,double r) {//辛普森积分 
    double mid=(l+r)/2;
    return (fun(l)+4*fun(mid)+fun(r))*(r-l)/6.0;
}

double asr(double l,double r,double eps,double s) {//自适应辛普森积分 
    double mid=(l+r)/2;
    double ls=sps(l,mid);
    double rs=sps(mid,r);
    if (fabs(ls+rs-s)<=(eps*15)) {
        return ls+rs+(ls+rs-s)/15.0;
    }
    return asr(l,mid,eps/2,ls)+asr(mid,r,eps/2,rs);
}

int main() {
    scanf("%lf",&a);
    if (a<0) {
        puts("orz");
    }
    else {
        printf("%.5lf",asr(1e-8,20,1e-8,sps(1e-8,20)));
    }
    return 0;
}

另外以上方法还可以解决多边形与圆的面积并问题,这样就不用写扫描线啦~\(≧▽≦)/~

阅读原文

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 自适应Simpson积分是一种数值积分,可以用于计算函数在给定区间上的积分值。在Matlab中,可以使用内置函数“quad”来实现自适应Simpson积分。具体步骤如下: 1. 定义被积函数f(x)。 2. 使用“quad”函数进行积分计算,语为: quad(f,a,b) 其中,f为被积函数,a和b为积分区间的上下限。 3. 如果需要更高的精度,可以使用“quadl”函数进行积分计算,语为: quadl(f,a,b,tol) 其中,tol为误差容限,即当积分误差小于tol时,积分计算停止。 需要注意的是,自适应Simpson积分适用于连续函数,如果被积函数在积分区间上不连续或有间断点,需要进行分段积分。 ### 回答2: 自适应Simpson积分是一种常用的数值积分,它基于辛普森公式,能够在不同精度要求下,自适应地选取合适的分割数,从而达到更高的精度。在Matlab中实现自适应Simpson积分需要以下步骤: 1. 编写Simpson积分的函数subSimpson,该函数接受一个函数句柄和积分上下限为参数,返回积分值。 2. 设置初始的精度要求tol和分割数N0。将整个积分区间[a,b]均匀地分割成N0个子区间,计算每个子区间的积分值,求和得到这一级别的积分结果S1。 3. 将整个积分区间再次均匀地分割,得到2N0个子区间。根据辛普森公式计算每个子区间的积分值,并利用这些结果得到更加精细的积分值S2。 4. 计算收敛因子Q=(S2-S1)/15,如果Q小于指定的精度要求tol,则返回S2作为积分结果;否则,将积分区间再次分割,进入第三步。 5. 在分割过程中,可以记录下每一级别的积分值和分割数,以便于后续的分析和统计。 Matlab代码示例: ```matlab function [I,n] = adaptSimpson(f,a,b,tol,N0) % f: 被积函数 % a,b: 积分区间 % tol: 精度要求 % N0: 初始分割数 x = linspace(a,b,2*N0+1); h = (b-a)/N0/2; y = f(x); S1 = sum(y(1:2:end-2)+4*y(2:2:end-1)+y(3:2:end)); S2 = sum(y(1:2:end-2)+4*y(2:2:end-1)+2*y(3:2:end-1)+4*y(4:2:end)+y(5:2:end)); I = S2/15*h; n = N0; Q = (S2-S1)/15; while abs(Q) > tol N = 2*n; x = linspace(a,b,2*N+1); y = f(x); S1 = S2; S2 = sum(y(1:2:end-2)+4*y(2:2:end-1)+2*y(3:2:end-1)+4*y(4:2:end)+y(5:2:end)); I = S2/15*h; n = N; Q = (S2-S1)/15; end end ``` 代码中,我们先根据初始的分割数N0,计算出积分区间的所有节点x,并根据辛普森公式计算出这一级别的积分结果S1和下一级别的积分结果S2。如果S2满足精度要求,则直接返回;否则,我们将分割数翻倍,重新计算节点和积分结果,进入下一级别的计算。当S2满足精度要求后,我们返回积分结果I和分割数n。 总之,自适应Simpson积分是一种高效的数值积分,通过递归的方式自适应地调整分割数,从而实现更高的精度。在Matlab中实现自适应Simpson积分,需要熟悉辛普森公式和递归算的基本原理。 ### 回答3: 自适应Simpson积分是一种数值积分,可用于计算函数的定积分。该方是通过将定积分区间分割成若干个子区间,每个子区间采用Simpson公式来计算积分值,从而得到整个区间的积分值。与传统的Simpson积分相比,自适应Simpson积分可以更准确地估计积分值,且能够自动适应积分函数的变化以提高计算效率。 在Matlab中,实现自适应Simpson积分的基本思路如下: 1. 将积分区间[a,b]分割成若干个子区间,每个子区间采用Simpson公式计算积分值I1。 2. 将整个区间[a,b]再分割成若干个子区间,每个子区间采用两个子区间的Simpson积分值之和减去一个子区间的Simpson积分值来计算积分值I2。 3. 计算误差E=abs(I2-I1)/15,如果E大于预设的误差精度tolerance,则将整个区间继续分割,否则返回I2作为最终的积分值。 该方的优点在于能够自动适应积分函数的变化,从而提高计算精度和效率。具体实现时,需要使用递归方来实现自动区间分割,同时需要设置适当的最大分割次数以避免程序陷入死循环。 Matlab中自适应Simpson积分的函数形式如下: function[result, err] = adaptive_simpson(f, a, b, tolerance, max_depth) % f为要积分的函数,a和b为积分区间的下限和上限,tolerance为误差精度,max_depth为最大分割次数 depth = 1; % 初始化分割次数为1 [result, err] = simpson_rule(f, a, b); % 计算初始的积分值和误差 while (depth < max_depth) && (err > tolerance) % 如果分割次数未达到最大值且误差仍然大于误差精度 depth = depth + 1; % 分割次数加1 [result_left, err_left] = simpson_rule(f, a, (a+b)/2); % 计算左半区间的积分值和误差 [result_right, err_right] = simpson_rule(f, (a+b)/2, b); % 计算右半区间的积分值和误差 result = result_left + result_right; % 计算整个区间的积分值 err = err_left + err_right; % 计算整个区间的误差 end 其中simpson_rule函数为Simpson积分公式的实现,具体如下: function[result, err] = simpson_rule(f, a, b) % f为要积分的函数,a和b为积分区间的下限和上限 result = (b-a)/6 * (f(a) + 4*f((a+b)/2) + f(b)); % 计算Simpson积分值 err = (b-a)^5 / 2880 * max(abs(diff(f([a,b,(a+b)/2])))); % 计算误差 end 需要注意的是,在实现自适应Simpson积分时,需要确保积分函数在积分区间内具有充分的平滑性和连续性,否则可能导致计算误差过大或发生计算异常。因此在应用该方时,需要首先对积分函数进行充分的分析和预处理,以保证计算结果的准确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值