自适应辛普森法 $1$
- 备注:
因为($C$ 是常数):
同样:
上面的定积分连接中有详细讲解(或者定积分的链接中)。
代码
套公式即可。
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<vector>
#include<random>
#include<ctime>
using namespace std;
long long r_r(){//快读
long long k=0,f=1;
char c=getchar();
while(!isdigit(c)){
if(c=='-')f=-1;
c=getchar();
}
while(isdigit(c)){
k=(k<<1)+(k<<3)+(c^48);
c=getchar();
}
return k*f;
}
double a,b,c,d,l,r;
double f(double x){
return (c*x+d)/(a*x+b);
}
double s_p(double l,double r){
double m_i=(l+r)/2;
return (f(l)+4*f(m_i)+f(r))*(r-l)/6;
}
double g_a(double l,double r,double m_n,double a_s){
double m_i=(l+r)/2;
double n_l=s_p(l,m_i);
double n_r=s_p(m_i,r);
if(fabs(n_l+n_r-a_s)<=15*m_n)return n_l+n_r+(n_l+n_r-a_s)/15;
return g_a(l,m_i,m_n/2,n_l)+g_a(m_i,r,m_n/2,n_r);
}
int main() {
scanf("%lf%lf%lf%lf%lf%lf",&a,&b,&c,&d,&l,&r);
printf("%.6lf",g_a(l,r,1e-6,s_p(l,r)));
return 0;
}
自适应辛普森法 2
$a < 0$ 发散
$a\ge 0$ 收敛
将区段(可以找右端点值,右端点之后的贡献在精度承受范围内)不断缩小(二分),误差在精度承受范围内,套用自适应辛普森法 $1$ 的公式累计结果即可。
扩展一个公式(解释代码中 $15$ 的来源):
代码
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<vector>
#include<random>
#include<ctime>
using namespace std;
long long r_r(){//快读
long long k=0,f=1;
char c=getchar();
while(!isdigit(c)){
if(c=='-')f=-1;
c=getchar();
}
while(isdigit(c)){
k=(k<<1)+(k<<3)+(c^48);
c=getchar();
}
return k*f;
}
const double m_n=1e-10;
double a,l,r;
double f(double x){
return pow(x,(a/x)-x);
}
double s_p(double p,double q){
double k=p+(q-p)/2;
return (f(p)+4*f(k)+f(q))*(q-p)/6.0;
}
double f_s(double p,double q,double k){
double k=p+(q-p)/2;
double l_l=s_p(p,k);
double r_r=s_p(k,q);
if(fabs(l_l+r_r-k)<=15*m_n)return l_l+r_r;
else return f_s(p,k,l_l)+f_s(k,q,r_r);
}
int main(){
scanf("%lf",&a);
if(a<0){
printf("orz");
return 0;
}
printf("%.5lf",f_s(m_n,15,s_p(l,r)));
return 0;
}