自适应simpson裸题
自适应辛普森:
simpson公式这样估计一段积分的值:对于F函数,a到b这一段的积分近似等于S(period)=(F(a)+F(b)+4*F(mid))/6*(b-a),即认为近似为一个常数积分,常数等于(F(a)+F(b)+4*F(mid))/6,其中mid=(b-a)/2。
如果F函数波动剧烈,这个估计方法会很不准。所以自适应辛普森会自动在波动大的地方对区间分隔的更细,在进行估计。
判断方法:设将当前区间P分为L,R两个区间,若fabs(S(L)+S(R)-S(P))>15*eps,则需要重新细分。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int aa,bb;
double F(double x){
return sqrt(bb*bb-x*x*bb*bb/(aa*aa));
}
double simpson(double a,double b){
double c=a+(b-a)/2;
return (F(a)+4*F(c)+F(b))*(b-a)/6;
}
double asr(double a,double b,double eps,double A){
double c=a+(b-a)/2;
double L=simpson(a,c),R=simpson(c,b);
if(fabs(L+R-A)<=15*eps) return L+R+(L+R-A)/15.0;
return asr(a,c,eps/2,L)+asr(c,b,eps/2,R);
}
double asr(double a,double b,double eps){
return asr(a,b,eps,simpson(a,b));
}
int main(){
int T;
scanf("%d",&T);
while(T--){
int l,r;
scanf("%d%d%d%d",&aa,&bb,&l,&r);
printf("%.3f\n",asr(l,r,1e-6)*2);
}
return 0;
}