题解 P4525 【【模板】自适应辛普森法1】
更好的阅读体验请参考我的博客
Simpson公式
在学习Simpson公式之前最好要对定积分有一个基本的了解,不过不了解也没有关系 (比如我)
Simpson公式就是在积分区间
定积分计算方法
定积分就是求函数
这里的面积是有正负的,
如何计算呢,可以用把区间分成几个小区间然后把小区间的积分求解再求和的方法,这时候就要用到Simpson公式了
Simpson公式推导
推导过程除了一个步骤其余都是初中内容了,推导过程如下
设
然后就得到了Simpson公式
用C++语言描述如下
inline double simpson(double l,double r) {
double mid=(l+r)/2;
return (f(l)+4*f(mid)+f(r))*(r-l)/6; //f(x)是原函数
}
自适应辛普森法
我们知道了定积分的计算方法,也知道了Simpson公式,按理说可以计算了。
但是有一个很重要的问题需要注意:精度。
区间分少了精度可能不够,区间分多了又会太慢,自动控制区间分割的大小,就是自适应辛普森法的好处。
实现很简单,就是二分递归的过程,如果满足了精度需要,则可以终止递归,而这就是自适应辛普森法能够自动控制区间分割大小的手段。
代码如下
double asr(double l,double r,double eps,double ans) {
double mid=(l+r)/2;
double l_=simpson(l,mid),r_=simpson(mid,r);
if(fabs(l_+r_-ans)<=15*eps) return l_+r_+(l_+r_-ans)/15;
return asr(l,mid,eps/2,l_)+asr(mid,r,eps/2,r_);
}
inline double asr(double l,double r,double eps) {
return asr(l,r,eps,simpson(l,r));
}
调用的时候只要给出区间起点和终点和需要的精度就可以了
这个题的话直接套板子就没有问题,注意精度精确到1e-6
#include <bits/stdc++.h>
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) { //Simpson公式
double mid=(l+r)/2;
return (f(l)+4*f(mid)+f(r))*(r-l)/6;
}
double asr(double l,double r,double eps,double ans) {
double mid=(l+r)/2;
double l_=simpson(l,mid),r_=simpson(mid,r);
if(fabs(l_+r_-ans)<=15*eps) return l_+r_+(l_+r_-ans)/15; //确认精度
return asr(l,mid,eps/2,l_)+asr(mid,r,eps/2,r_); //精度不够则递归调用
}
inline double asr(double l,double r,double eps) {
return asr(l,r,eps,simpson(l,r));
}
int main() {
scanf("%lf%lf%lf%lf%lf%lf",&a,&b,&c,&d,&l,&r);
printf("%.6lf",asr(l,r,1e-6));
return 0;
}