天天看點

ACM模闆——自适應辛普森積分

一、概念

辛普森積分是數值積分的一種,是中點公式和梯形公式的改進。

二、解析

假定我們要求如下定積分:

ACM模闆——自适應辛普森積分
ACM模闆——自适應辛普森積分

略微懂一點微積分知識的都知道,對于一個黎曼可積的函數,我們要求其在某個閉區間上的定積分,要先求該函數的不定積分,即先求原函數。就是找到一個函數 F(x),使得 F′(x)=f(x),然後根據牛頓—萊布尼茨公式去搞。即:

而有時候原函數并不好求,比如要求原的函數長得很複雜,要求的原函數非初等函數。這時我們需要“避其鋒芒”,采用一種利用“近似”思想的方法。

我們都知道定積分就是曲線 f(x) 下方的面積(假設 f(x) 恒大于 0 ),我們考慮一種近似求出曲線下方面積的方法——辛普森法。

我們先在區間[a,b]中等距地取奇數個點a=x0,x1,x2,...,xn=b,相鄰兩點間的距離為Δx,再設yi=f(xi),然後套用公式:

ACM模闆——自适應辛普森積分

點取得越多,近似程度就越高,但計算量也越大。當隻取三個點的時候,有:

ACM模闆——自适應辛普森積分

這就是三點辛普森公式,又簡稱辛普森公式。

然而如果隻取三個點誤差肯定大,取太多的點計算量也會上去。那麼到底取多少個點合适呢?

還好辛普森積分有一個重要的“變種”,稱為自适應辛普森法(adaptive Simpson’s rule),我們設定一個精度Eps,讓算法根據具體情況遞歸的劃分區間,容易近似的地方少劃幾份,不容易近似的地方多劃幾份。這就是所謂的“自适應”。

具體的話,就是設區間 [a,b] 的中點為 c,則當且僅當:

ACM模闆——自适應辛普森積分

時(加==亦可)直接傳回結果,否則遞歸調用,再次劃分區間。遞歸調用時精度Eps也要相應地減小一半。 Ps: 

ACM模闆——自适應辛普森積分

三、總結

四、代碼

double f(double x)
{
    return b * sqrt(1 - (x * x) / (a * a)); // 寫要求辛普森積分的函數,如:橢圓公式 y 表達式
}

double simpson(double a, double b) // 三點辛普森積分法,要求f(x)是全局函數
{ 
    double c = a + (b - a) / 2;
    return (f(a) + 4 * f(c) + f(b)) * (b - a) / 6;
}

double integral(double L, double R, double Eps) // 自适應辛普森積分遞歸過程
{ 
    // 這裡 mid 不能定義為全局變量,因為最後一條 return 有兩個 mid 若是全局,第二個遞歸的 mid 會有更換
    double mid = L + (R - L) / 2;
    double ST = simpson(L, R), SL = simpson(L, mid), SR = simpson(mid, R);
    if(fabs(SL + SR - ST) <= 15 * Eps)  return SL + SR + (SL + SR - ST) / 15; // 直接傳回結果
    // 若這裡直接 return ST; 會 WA
    return integral(L, mid, Eps/2) + integral(mid, R, Eps/2); // 對半劃分區間
}