自適應辛普森積分學習筆記

辛普森積分:

辛普森(Simpson)公式是牛頓-科特斯公式當n=2時的情形,也稱爲三點公式。利用區間二等分的三個點來進行積分插值。其科特斯係數分別爲1/6,4/6,1/6。(百度百科)
它可以用來求三次及三次以內的函數積分,在三次及三次以內辛普森積分是精確的。
它的表達式是這樣的:

abf(x)dx=ba6×[f(a)+4×f(a+b2)+f(b)]

自適應辛普森積分:

它的用處遠不止求解三次以下的函數,對於任意一段函數,我們也可以利用辛普森積分來求解積分的近似值。
具體來講就是不斷地將當前的區間二分,把這一段的積分轉化爲兩個子問題,使得求解的區間更小,同時使得答案更加精確。爲了保證複雜度,當目前所求的答案和正確答案相差不大時便可以返回,至於如何判斷,可以利用左區間答案+右區間答案和整個區間答案的差值。
綜上所述,可以得出其基本思想是將一段不規則的函數不斷擬合成三次或三次以下的函數,達到接近答案的解時即可返回。
例題:hdu1724
注意代碼中的eps的判斷,這樣可以比較好地保證精度。

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;
typedef double db;

using namespace std;

void File(){
    freopen("hdu1724.in","r",stdin);
    freopen("hdu1724.out","w",stdout);
}

const db eps=1e-5;
int n;
db a,b,L,R;

db fun(db x){return sqrt(b*b-b*b/a/a*x*x);}

db simpson(db l,db r){return (r-l)/6*(fun(l)+4*fun((l+r)/2)+fun(r));}

db solve(db l,db r,db e){
    db mid=(l+r)/2,s0=simpson(l,r),s1=simpson(l,mid),s2=simpson(mid,r);
    if(fabs(s1+s2-s0)<e*15)return s1+s2+(s1+s2-s0)/15;
    return solve(l,mid,e/2)+solve(mid,r,e/2);
}

int main(){
    File();
    scanf("%d",&n);
    while(n--){
        scanf("%lf%lf%lf%lf",&a,&b,&L,&R);
        printf("%.3lf\n",solve(L,R,eps)*2);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章