自适应辛普森公式求积分
第一回接触辛普森积分,至于这个辛普森是干嘛的呢,在这里就有必要好好地讲一讲了。
来源:辛普森(Simpson)公式是牛顿-科特斯公式当n=2时的情形,也称为三点公式。利用区间二等分的三个点来进行积分插值。其科特斯系数分别为1/6,4/6,1/6。
应用:立体几何中用来求拟柱体体积的公式。
这里就不详细说辛普森公式了,有需要的朋友可以看这里:https://baike.baidu.com/item/%E8%BE%9B%E6%99%AE%E6%A3%AE%E5%85%AC%E5%BC%8F/9255085?fr=aladdin
接下来我们好好的说说自适应辛普森公式求积分,自适应辛普森公式求积分是很重要的一个知识点,弄懂了自适应辛普森公式求积分就能明白辛普森积分是干嘛的了,
下面的内容是重点!!!:
假设我们求以下积分:
比较特殊的情况,就是可以推导出来最后的形式。但是比较一般的情况是,我们只能大致得到一个XY坐标系里的曲线,我们求的就是曲线和X轴所围成的面积。
因此我们有自适应辛普森公式,他会根据实际情况来自动的调整精度。
它的大致过程就是,给定一个要求达到的精度eps,算法就会根据实际情况递归的划分区间。容易近似的地方少划分,不容易近似的地方多划分几份。
具体来讲,我们在以下情况下直接返回结果,否则递归划分区间:
具体参考博客:http://blog.csdn.net/frosero/article/details/45799135
下面举个例题:hdu-1724
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1724
题目大意:题目就是求两条线所夹的椭圆的面积。这是个标准的椭圆,其中心在原点。我好像看到了题目连椭圆面积公式都给了,然而并没有任何用,直接上辛普森!
根据椭圆的对称性,我们求x轴上方的面积然后乘以2就是答案。根据椭圆方程x2a2+y2b2=1,构造函数y=。。。其中y>0,然后对此函数进行自适应辛普森积分就可以了。
写完程序过了样例后立马交,TLE,1000ms。结果发现是Eps取的太小了,取了1e-10,随着递归下去,Eps不断除以2,导致不断递归划分,做的次数很多就超时了。这题只要求保留3位小数,所以精度没有太大问题,将Eps改为1e-5立马就AC了,109ms。
ac代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ri(n) scanf("%d",&n)
#define oi(n) printf("%d\n",n)
#define rl(n) scanf("%lld",&n)
#define ol(n) printf("%lld\n",n)
#define rep(i,l,r) for(i=l;i<=r;i++)
#define rep1(i,l,r) for(i=l;i
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const double eps=1e-5;//这里的eps是整个辛普森应用的关键,至于取多大,得依题目而定
double a,b,l,r;
double f(double x)//这里的f函数是自己根据题目推导出来的,主要还是x有关y的函数
{
double y=b*sqrt(1.0-(x*x)/(a*a));
return y;
}
double simpson(double a,double b)//这里是辛普森公式
{
double c=(a+b)/2.0;
return (f(a)+f(b)+4.0*f(c))*(b-a)/6.0;
}
double ars(double a,double b,double eps)//这里就是递归求辛普森最重要的一段函数了,
{
double c=(a+b)/2.0;
double mid=simpson(a,b),l=simpson(a,c),r=simpson(c,b);
if(fabs(l+r-mid)<=15*eps)
return l+r+(l+r-mid)/15.0;
return ars(a,c,eps/2.0)+ars(c,b,eps/2.0);
}
int main()
{
int t;
ri(t);
while(t--)
{
scanf("%lf%lf%lf%lf",&a,&b,&l,&r);
printf("%.3lf\n",2.0*ars(l,r,eps));//递归求辛普森
}
return 0;
}