1. 程式人生 > 實用技巧 >自適應Simpson積分

自適應Simpson積分

用$g(x)=A*x^2+B*x+C$來代替原函式$f(x)$,設$g(x)$原函式為$G(x)$,顯然$G(x)=\frac{1}{3}*A*x^3+\frac{1}{2}*B*x^2+C*x$

$\int_a^b f(x) dx \approx \int_a^b g(x) dx=G(b)-G(a)$

代入化簡得

$$\int_a^b f(x) dx \approx \frac{a-b}{6}*[g(a)+g(b)+4*g(\frac{a+b}{2})]$$

二分割槽間,然後計算區間積分,通過期望容差來控制二分

如果$|S(a,mid)+S(mid,b)-S(a,b)|<15*\varepsilon$,則中止二分,並且認為

$$S(a,b)=S(a,m)+S(m,b)+\frac{S(a,mid)+S(mid,b)-S(a,b)}{15}$$

否則繼續二分

其中$mid=\frac{a+b}{2},\varepsilon為期望容差$

參考部落格:https://www.cnblogs.com/chy-2003/p/11644112.html

例題:

hdu 1724

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>

using
namespace std; int T; double a, b, l, r; inline double sqr(double x) { return x * x; } double f(double x) { double t = sqr(b) - sqr(b) / sqr(a) * sqr(x); return 2 * sqrt(t); } double calc(double l, double r) { double mid = (l + r) / 2; return (f(l) + 4 * f(mid) + f(r)) * (r - l) / 6
; } double simpson(double l, double r, double eps) { double mid = (l + r) / 2; double st = calc(l, r), sl = calc(l, mid), sr = calc(mid, r); if (fabs(sl + sr - st) <= 15 * eps) return sl + sr + (sl + sr - st) / 15; return simpson(l, mid, eps / 2) + simpson(mid, r, eps / 2); } int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); scanf("%d", &T); while (T--) { scanf("%lf%lf%lf%lf", &a, &b, &l, &r); printf("%.3lf\n", simpson(l, r, 1e-6)); } return 0; }