一个数学算法,用于求积分。

积分

        既然都学过高数,就不多说了这里需要先了解定积分,形如下面的形式:

        求解积分是一个十分具有实际意义的操作,辛普森积分法就是一种重要的求解方法。

辛普森法

        辛普森法的思想是用二次函数来拟合原函数。现在我们用这样一个函数来拟合:

        那么就是求:

        下面求这个积分就好了:

        然后就化这个式子,并注意到$f(x)$近似就是$g(x)$,最后可以化成这个样:

        这个式子称为辛普森积分公式,它给出了求一个函数积分的估计值。
        区间很大时,这种计算的误差相当大,当区间不断细分时它的准确率就会不断上升。现在需要将区间细分,以达到提高精度的效果。但是区间不宜过多,这样时间消耗太大,又不宜过少,这样就不能满足精度。对于一个给定的精度,如果程序能够动态调整其划分区间的策略,那么就可以同时满足效率和精度的要求了,这就是自适应辛普森法。
        自适应辛普森法的代码十分短小精悍:

1
2
3
4
5
6
7
8
9
10
11
12
inline double simpson(double l, double r) {//辛普森公式,f就是积分函数,需要自己定义
double mid = (l + r) / 2;
return (f(l) + f(r) + 4.0 * f(mid)) * (r - l) / 6.0;
}

double asr(double l, double r, double ans, double eps) {//eps是精度,可取1e-6,ans是估计答案
double mid = (l + r) / 2;
double ll = simpson(l, mid), rr = simpson(mid, r);//左右半区间分治
if (fabs(ll + rr - ans) <= 15 * eps)return ll + rr + (ll + rr - ans) / 15.0;//满足精度需求,直接返回
return asr(l, mid, ll, eps / 2.0) + asr(mid, r, rr, eps / 2.0);//不满足继续分治
}


        上面的写法是一种通用写法,其中为什么需要乘上15,我也不知道(逃。
        自适应辛普森法其实是一个很板子的代码,基本也不需要多少复杂的变化,当成一个知识点了解一下吧。
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
#include <bits/stdc++.h>

using namespace std;
double a, b, c, d, l, r;

inline double f(double x) {//这里定义函数
return (c * x + d) / (a * x + b);
}

inline double simpson(double l, double r) {
double mid = (l + r) / 2;
return (f(l) + f(r) + 4.0 * f(mid)) * (r - l) / 6.0;
}

double asr(double l, double r, double ans, double eps) {
double mid = (l + r) / 2;
double ll = simpson(l, mid), rr = simpson(mid, r);
if (fabs(ll + rr - ans) <= 15 * eps)return ll + rr + (ll + rr - ans) / 15.0;
return asr(l, mid, ll, eps / 2.0) + asr(mid, r, rr, eps / 2.0);
}

int main() {
cin >> a >> b >> c >> d >> l >> r;
printf("%.6f", asr(l, r, simpson(l, r), 1e-6));//这样使用
return 0;
}