前言
前言
simpson积分
simpson积分公式
∫ a b f ( x ) d x ≈ b − a 6 [ f ( a ) + f ( b ) + 4 f ( a + b 2 ) ] \int_{a}^{b}f(x)dx \approx \frac{b-a}{6}[f(a)+f(b)+4f(\frac{a+b}{2})] ∫abf(x)dx≈6b−a[f(a)+f(b)+4f(2a+b)]
与梯形积分类似,当区间[a,b]较大时,积分与实际相差较大。
复化simpson积分
假设区间[a,b]被划分为n个小区间,则有区间间隔为 h = b − a n , x k = a + k h ( k = 0 , ⋯ , n ) h=\frac{b-a}{n},x_k=a+kh(k=0,\cdots,n) h=nb−a,xk=a+kh(k=0,⋯,n),对于每一个小区间都有:
∫ x k x k + 1 f ( x ) d x ≈ h 6 [ f ( x k ) + f ( x k + 1 ) + 4 f ( x k + 1 2 ) ] \int _{x_k}^{x_{k+1}}f(x)dx \approx \frac{h}{6}[f(x_k)+f(x_{k+1})+4f(x_{k+\frac{1}{2}})] ∫xkxk+1f(x)dx≈6h[f(xk)+f(xk+1)+4f(xk+21)]
在[a,b]区间内进行累加可以得到
∫ a b f ( x ) d x ≈ h 6 [ f ( a ) + f ( b ) + 2 ∑ k = 0 n − 1 f ( x k + 1 ) + 4 ∑ k = 0 n − 1 f ( x k + 1 2 ) ] = S n \int _{a}^{b}f(x)dx \approx \frac{h}{6}[f(a)+f(b)+2\sum_{k=0}^{n-1}f(x_{k+1})+4\sum_{k=0}^{n-1}f(x_{k+\frac{1}{2}})]=S_n ∫abf(x)dx≈6h[f(a)+f(b)+2k=0∑n−1f(xk+1)+4k=0∑n−1f(xk+21)]=Sn
误差分析
复化simpson积分的余项为: R [ f ] = − b − a 180 ( h 2 ) 4 f ( 4 ) ( ξ ) = − ( b − a ) 5 2880 n 4 f ( 4 ) ( ξ ) R[f]=-\frac{b-a}{180}(\frac{h}{2})^4f^{(4)}(\xi)\\ =-\frac{(b-a)^5}{2880n^4}f^{(4)}(\xi) R[f]=−180b−a(2h)4f(4)(ξ)=−2880n4(b−a)5f(4)(ξ)
与梯形积分相似,对其加密一倍n,可以得到对应的事后误差估计公式:
S 2 n ( f ) − s n ( f ) < 15 ϵ S_{2n}(f)-s_n(f)< 15\epsilon S2n(f)−sn(f)<15ϵ
可以等价于:
I ( f ) − S 2 n ( f ) < ϵ I(f)-S_{2n}(f)< \epsilon I(f)−S2n(f)<ϵ
代码
#include<iostream>
#include<cmath>
#include<iomanip>//这个头文件仅仅是用来设置cout的输出精度
#define abs(x) (x>0?x:-x)
using namespace std;
double Simpson(int n,double a,double b,float(*f)(float x))
{double f_x=0.0f;double h=(b-a)/n;for(int i=0;i<n;i++){f_x+=4*f(a+i*h+h/2);//算f(x_(k+1/2))}for(int i=1;i<n;i++){f_x+=2*f(a+i*h);//算f(x_(k+1))}f_x+=f(a)+f(b);f_x=f_x*h/6;return f_x;
}
//直接在这里换函数,函数为sin(x)/x
float fx(float x)
{float result;float x_temp=((x==0)?1e-15:x);result=sin(x_temp)/x_temp;return result;
}
int main()
{double error=1e-6;//表示误差小于10^-6次方double a = 0.0, b = 2.0;int n=1;double f_x_n=(fx(a)+fx(b))*(b-a)/2;double f_x_2n;while(true){f_x_2n=Simpson(n*2,a,b,fx);//算T2nif(fabs(f_x_n-f_x_2n)<(error*15)){// cout<<n<<":simposon error="<<fabs(f_x_n-f_x_2n)<<endl;// printf("%.8f,%.8f\n",f_x_n,f_x_2n);cout << "Simpson积分的误差为:" << fabs(f_x_n - f_x_2n) << endl;n*=2;break;}n+=1;f_x_n=Simpson(n,a,b,fx);}cout<<"区间划分数量:n="<<n<<",积分值为:"<<std::setprecision(10)<<f_x_2n<<endl;return 0;
}
结果分析
与梯形积分相比,在相同的被积函数和积分区间上,为了达到一样的误差范围,其迭代次数更少:
使用matlab进行对比可以得到:
可以看出其实际误差已经达到了期望。