对于一个二次函数 f ( x ) = a x 2 + b x + c f(x) = ax^2 + bx + c f(x)=ax2+bx+c,积分得 F ( x ) = ∫ 0 x f ( t ) d t = a 3 x 3 + b 2 x 2 + c x + C F(x) = \displaystyle\int_0^x f(t) \, \mathrm{d}t = \dfrac{a}{3}x^3 + \dfrac{b}{2}x^2 + cx + C F(x)=∫0xf(t)dt=3ax3+2bx2+cx+C。
于是
∫ l r f ( x ) d x = F ( r ) − F ( l ) \displaystyle\int_l^r f(x) \, \mathrm{d}x = F(r) - F(l) ∫lrf(x)dx=F(r)−F(l)
= a ( r 3 − l 3 ) 3 + b ( r 2 − l 2 ) 2 + c ( r − l ) + ( C − C ) = \dfrac{a(r^3 - l^3)}{3} + \dfrac{b(r^2 - l^2)}{2} + c(r - l) + (C - C) =3a(r3−l3)+2b(r2−l2)+c(r−l)+(C−C)
= ( r − l ) [ a ( r 2 + r l + l 2 ) 3 + b ( r + l ) 2 + c ] = (r - l)[\dfrac{a(r^2 + rl + l^2)}{3} + \dfrac{b(r + l)}{2} + c] =(r−l)[3a(r2+rl+l2)+2b(r+l)+c]
= r − l 6 ( 2 a r 2 + 2 a r l + 2 a l 2 + 3 b r + 3 b l + 6 c ) = \dfrac{r - l}{6}(2ar^2 + 2arl + 2al^2 + 3br + 3bl + 6c) =6r−l(2ar2+2arl+2al2+3br+3bl+6c)
= r − l 6 { ( a r 2 + b r + c ) + ( a l 2 + b l + c ) + 4 [ a ( l + r 2 ) 2 + b ( l + r 2 ) + c ] } = \dfrac{r - l}{6}\{(ar^2 + br + c) + (al^2 + bl + c) + 4[a(\dfrac{l + r}{2})^2 + b(\dfrac{l + r}{2}) + c]\} =6r−l{(ar2+br+c)+(al2+bl+c)+4[a(2l+r)2+b(2l+r)+c]}
= ( r − l ) ( f ( l ) + 4 f ( l + r 2 ) + f ( r ) ) 6 = \dfrac{(r - l)(f(l) + 4f(\dfrac{l + r}{2}) + f(r))}{6} =6(r−l)(f(l)+4f(2l+r)+f(r))
以上即为辛普森公式。
普通辛普森法
为了求 ∫ l r f ( x ) d x \displaystyle\int^r_l f(x) \, \mathrm{d}x ∫lrf(x)dx,可以将区间 [ l , r ] [l, r] [l,r] 分为 2 n 2n 2n个等长的区间 [ g i , g i + 1 ] ( i ∈ { 1 , 2 , . . . , 2 n } ) [g_i, g_{i + 1}](i \in \{1, 2, ..., 2n\}) [gi,gi+1](i∈{1,2,...,2n})。设 h = r − l 2 n h = \dfrac{r - l}{2n} h=2nr−l,近似地计算过 ( g i − 1 , f ( g i − 1 ) ) (g_{i - 1}, f(g_{i - 1})) (gi−1,f(gi−1))、 ( g i , f ( g i ) ) (g_i, f(g_i)) (gi,f(gi))、 ( g i + 1 , f ( g i + 1 ) ) (g_{i + 1}, f(g_{i + 1})) (gi+1,f(gi+1)) 三点的二次函数在区间 [ g i − 1 , g i + 1 ] [g_{i - 1}, g_{i + 1}] [gi−1,gi+1] 的积分。当 n n n 足够大时,计算结果便越接近原函数的积分。设 P ( x ) P(x) P(x) 为过该三点的函数,则
∫ l r f ( x ) d x ≈ ∑ i = 1 n ∫ g 2 i − 1 g 2 i + 1 P ( x ) d x \displaystyle\int^r_l f(x) \, \mathrm{d}x \approx \displaystyle\sum_{i = 1}^{n} \displaystyle\int^{g_{2i + 1}}_{g_{2i - 1}} P(x) \, \mathrm{d}x ∫lrf(x)dx≈i=1∑n∫g2i−1g2i+1P(x)dx
= h 3 ( ∑ i = 1 n f ( g 2 i − 1 ) + 4 f ( g 2 i ) + f ( g 2 i + 1 ) ) = \dfrac{h}{3} (\displaystyle\sum^{n}_{i = 1} f(g_{2i - 1}) + 4f(g_{2i}) + f(g_{2i + 1})) =3h(i=1∑nf(g2i−1)+4f(g2i)+f(g2i+1))
= h 3 ( f ( g 1 ) + 4 f ( g 2 ) + 2 f ( g 3 ) + 4 f ( g 4 ) + . . . + 2 f ( g 2 n − 1 ) + 4 f ( g 2 n ) + f ( g 2 n + 1 ) ) = \dfrac{h}{3}(f(g_1) + 4f(g_2) + 2f(g_3) + 4f(g_4) + ... + 2f(g_{2n - 1}) + 4f(g_{2n}) + f(g_{2n+1})) =3h(f(g1)+4f(g2)+2f(g3)+4f(g4)+...+2f(g2n−1)+4f(g2n)+f(g2n+1))
Code:
int n = 1e7;
double calc(double l, double r) {
double h = (r - l) / (2 * n), res = f(l) + f(r);
for (int i = 2; i < 2 * n; ++i)
res += f(l + i * h) * (i & 1? 2: 4);
return res * h / 3;
}
自适应辛普森法
考虑到当分割出的二次函数在该区间内已经足够接近原函数时,可以直接使用该积分值;而当二次函数仍不够接近时还需再分割,于是可以考虑分别用辛普森公式计算区间 [ l , r ] [l, r] [l,r]、 [ l , l + r 2 ] [l, \dfrac{l + r}{2}] [l,2l+r]、 [ l + r 2 , r ] [\dfrac{l + r}{2}, r] [2l+r,r] 的积分值,若大区间的积分值与小区间的积分值和的差足够小,则可以认为二次函数的图像在该区间内足够接近原函数的图像,并直接返回大区间的积分值。否则,递归计算两个小区间。一般还需设定一个次数,当已经递归超过该次数时才开始判断是否可以直接返回。
P4525 【模板】自适应辛普森法 1 AC Code:
#include <cstdio>
#define simpson(l, r) ((r - l) * (f(l) + f(r) + 4 * f((l + r) / 2)) / 6)
#define f(x) (double(c * (x) + d) / (a * (x) + b))
#define abs(x) ((x) >= 0? (x): -(x))
using namespace std;
double a, b, c, d, L, R;
double calc(double l, double r, int step, double sps) {
double mid = (l + r) / 2;
double fl = simpson(l, mid), fr = simpson(mid, r);
if (abs(fl + fr - sps) <= 1e-6 && step < 0)
return sps;
else
return calc(l, mid, step - 1, fl) + calc(mid, r, step - 1, fr);
}
int main() {
scanf("%lf %lf %lf %lf %lf %lf", &a, &b, &c, &d, &L, &R);
printf("%lf", calc(L, R, 12, simpson(L, R)));
return 0;
}