牛顿-柯斯特(Newton-Cotes)求积公式是插值型求积公式的特殊形式
在插值求积公式
∫baf(x)dx≈∫baP(x)dx=∑k=0nAkf(xk) ∫ a b f ( x ) d x ≈ ∫ a b P ( x ) d x = ∑ k = 0 n A k f ( x k )
中所取节点是等距时称为牛顿-柯斯特公式
其中插值多项式
P(x)=∑k=0nℓk(x)f(xk) P ( x ) = ∑ k = 0 n ℓ k ( x ) f ( x k )
求积系数
Ak=∫baℓk(x)dx A k = ∫ a b ℓ k ( x ) d x
这里 ℓk(x) ℓ k ( x ) 指的是插值基函数,即有
Ak=∫baℓk(x)dx=∫ba∏j=0,j≠knx−xjxk−xjdx A k = ∫ a b ℓ k ( x ) d x = ∫ a b ∏ j = 0 , j ≠ k n x − x j x k − x j d x
在 [a,b] [ a , b ] 区间内设置等距的插值基点 a=x0<x1⋯<xn=b a = x 0 < x 1 ⋯ < x n = b ,设节点步长为 h=b−an,xk=a+kh,k∈{0,1,⋯,n} h = b − a n , x k = a + k h , k ∈ { 0 , 1 , ⋯ , n }
积分作变量替换 x=a+th x = a + t h
xk−xj=(k−j)h,x−xj=(t−j)h,dx=hdt x k − x j = ( k − j ) h , x − x j = ( t − j ) h , d x = h d t
(xk−x0)⋯(xk−xk−1)(xk−xk+1)⋯(xk−xn) ( x k − x 0 ) ⋯ ( x k − x k − 1 ) ( x k − x k + 1 ) ⋯ ( x k − x n )
=k(k−1)⋯1(−1)(−2)⋯(−(n−k))hn=(−1)n−kk!(n−k)!hn = k ( k − 1 ) ⋯ 1 ( − 1 ) ( − 2 ) ⋯ ( − ( n − k ) ) h n = ( − 1 ) n − k k ! ( n − k ) ! h n
(x−x0)⋯(x−xk−1)(x−xk+1)⋯(x−xn) ( x − x 0 ) ⋯ ( x − x k − 1 ) ( x − x k + 1 ) ⋯ ( x − x n )
=t(t−1)⋯(t−k+1)(t−k−1)⋯(t−n)hn = t ( t − 1 ) ⋯ ( t − k + 1 ) ( t − k − 1 ) ⋯ ( t − n ) h n
当 x=a x = a 时, t=0 t = 0 ,当 x=b x = b 时, t=n t = n
于是有 Ak=∫baℓk(x)dx=h∫n0t(t−1)⋯(t−k+1)(t−k−1)⋯(t−n)(−1)n−kk!(n−k)!dt A k = ∫ a b ℓ k ( x ) d x = h ∫ 0 n t ( t − 1 ) ⋯ ( t − k + 1 ) ( t − k − 1 ) ⋯ ( t − n ) ( − 1 ) n − k k ! ( n − k ) ! d t
=h⋅(−1)n−kk!(n−k)!∫n0t(t−1)⋯(t−k+1)(t−k−1)⋯(t−n)dt = h ⋅ ( − 1 ) n − k k ! ( n − k ) ! ∫ 0 n t ( t − 1 ) ⋯ ( t − k + 1 ) ( t − k − 1 ) ⋯ ( t − n ) d t
=nh⋅(−1)n−kk!(n−k)!n∫n0t(t−1)⋯(t−k+1)(t−k−1)⋯(t−n)dt = n h ⋅ ( − 1 ) n − k k ! ( n − k ) ! n ∫ 0 n t ( t − 1 ) ⋯ ( t − k + 1 ) ( t − k − 1 ) ⋯ ( t − n ) d t
=(b−a)⋅(−1)n−kk!(n−k)!n∫n0t(t−1)⋯(t−k+1)(t−k−1)⋯(t−n)dt = ( b − a ) ⋅ ( − 1 ) n − k k ! ( n − k ) ! n ∫ 0 n t ( t − 1 ) ⋯ ( t − k + 1 ) ( t − k − 1 ) ⋯ ( t − n ) d t
=(b−a)⋅(−1)n−kk!(n−k)!n∫n0∏j=0,j≠kn(t−j)dt = ( b − a ) ⋅ ( − 1 ) n − k k ! ( n − k ) ! n ∫ 0 n ∏ j = 0 , j ≠ k n ( t − j ) d t
不难发现,式子中的 (−1)n−kk!(n−k)!n∫n0∏j=0,j≠kn(t−j)dt ( − 1 ) n − k k ! ( n − k ) ! n ∫ 0 n ∏ j = 0 , j ≠ k n ( t − j ) d t 与步长h无关,所以可以预处理。我们将上述表达式称之为柯斯特求积系数,记为
c(n)k=(−1)n−kk!(n−k)!n∫n0∏j=0,j≠kn(t−j)dt c k ( n ) = ( − 1 ) n − k k ! ( n − k ) ! n ∫ 0 n ∏ j = 0 , j ≠ k n ( t − j ) d t
那么我们的求积系数
Ak=(b−a)c(n)k A k = ( b − a ) c k ( n )
于是求得牛顿-柯斯特公式
∫baf(x)dx≈(b−a)∑k=0nc(n)kf(xk) ∫ a b f ( x ) d x ≈ ( b − a ) ∑ k = 0 n c k ( n ) f ( x k )
上面你就当我装了一波逼,其实闷声背公式也是可以滴
我们将上述式子令n=1,得到柯斯特系数
c(1)0=−∫10(t−1)dt=12 c 0 ( 1 ) = − ∫ 0 1 ( t − 1 ) d t = 1 2
c(1)1=−∫10tdt=12 c 1 ( 1 ) = − ∫ 0 1 t d t = 1 2
于是得到梯形公式
I1(f)=(b−a)12f(a)+f(b−a)12f(b) I 1 ( f ) = ( b − a ) 1 2 f ( a ) + f ( b − a ) 1 2 f ( b )
梯形公式具有一次代数精确度(就是没什么卵用)
在立体几何中,辛普森积分用来计算拟柱体体积公式
设拟柱体的高(两底面 α,β α , β 间的距离)为H,如果用平行于底面的平面γ去截该图形,所得到的截面面积是平面 γ γ 与平面 α α 之间距离h的不超过3次的函数,那么该拟柱体的体积V为
V=H(S1+4S2+S3)6 V = H ( S 1 + 4 S 2 + S 3 ) 6
式中, S1 S 1 和 S2 S 2 是两底面的面积, S0 S 0 是中截面的面积
V=∫f(x)dx V = ∫ f ( x ) d x
=ah44+bh33+ch22+dh = a h 4 4 + b h 3 3 + c h 2 2 + d h
利用公式计算体积,可以得到:
V=H(S1+4S2+S3)6 V = H ( S 1 + 4 S 2 + S 3 ) 6
=h(f(0)+4f(h2)+f(h))/6 = h ( f ( 0 ) + 4 f ( h 2 ) + f ( h ) ) / 6
=16h[d+4(ah38+bh24+ch2+d)+(ah3+bh2+ch+d)] = 1 6 h [ d + 4 ( a h 3 8 + b h 2 4 + c h 2 + d ) + ( a h 3 + b h 2 + c h + d ) ]
=ah44+bh33+ch22+dh = a h 4 4 + b h 3 3 + c h 2 2 + d h
于是原命题得证
根据牛顿-柯斯特求积公式,令n=2,带入得到柯斯特系数
c(2)0=14∫20(t−1)(t−2)dt=16 c 0 ( 2 ) = 1 4 ∫ 0 2 ( t − 1 ) ( t − 2 ) d t = 1 6
c(2)1=−12∫20t(t−2)dt=46 c 1 ( 2 ) = − 1 2 ∫ 0 2 t ( t − 2 ) d t = 4 6
c(2)2=14∫20t(t−1)dt=16 c 2 ( 2 ) = 1 4 ∫ 0 2 t ( t − 1 ) d t = 1 6
于是有
I2(f)=(b−a)(16f(a)+46f(a+b2)+16f(b)) I 2 ( f ) = ( b − a ) ( 1 6 f ( a ) + 4 6 f ( a + b 2 ) + 1 6 f ( b ) )
=16(b−a)(f(a)+4f(a+b2)+f(b)) = 1 6 ( b − a ) ( f ( a ) + 4 f ( a + b 2 ) + f ( b ) )
这就是辛普森积分公式,说明了辛普森积分公式就是牛顿-柯斯特求积公式的特殊情况。
辛普森积分具有良好的稳定性与收敛性,在数值逼近领域有很重要的应用。
bzoj2178圆的面积并
辛普森积分不论具有多么优秀的稳定性与收敛性,在大数据范围内仍会出现较大误差。因此自适应辛普森积分算法是辛普森积分的衍生算法。其基本步骤如下
对于平面上的圆的面积并,我们首先排除内含的所有圆,然后建立函数模型f(a)表示在圆所覆盖直线x=a的线段长度。那么就有
ans=∫xmaxxminf(x) a n s = ∫ x m i n x m a x f ( x )
函数无法直接求出,于是我们采用自适应辛普森积分法即可。
(ps:这题卡精度,小心为妙)
/**************************************************************
Problem: 2178
User: 2014lvzelong
Language: C++
Result: Accepted
Time:4412 ms
Memory:1340 kb
****************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int N = 1101;
const double eps = 1e-6;
int read() {
char ch = getchar(); int x = 0, f = 1;
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) - '0' + ch; ch = getchar();}
return x * f;
}
struct C{
int x, y, r;
C(int xx = 0, int yy = 0, int rr = 0) : x(xx), y(yy), r(rr) {}
C operator - (C &a) {return C(x - a.x, y - a.y);}
int operator ^ (C &a) {return x * a.x + y * a.y;}
}c[N];
int n, st, ed, tot, L, R;
bool del[N];
struct Li{double l, r;}p[N];
int sqr(double x) {return x * x;}
int sqr(C a) {return a ^ a;}
bool cmp1(C a, C b) {return a.r < b.r;}
bool cmp2(C a, C b) {return a.x - a.r < b.x - b.r;}
bool cmp3(Li a, Li b) {return a.l < b.l;}
void Del() {
sort(c + 1, c + n + 1, cmp1);
for(int i = 1;i <= n; ++i)
for(int j = i + 1;j <= n; ++j)
if(sqr(c[i] - c[j]) <= sqr(c[j].r - c[i].r))
{del[i] = true; break;}
int top = 0;
for(int i = 1;i <= n; ++i) if(!del[i]) c[++top] = c[i];
n = top;
sort(c + 1, c + n + 1, cmp2);
}
double F(double x) {
double ret = 0; tot = 0;
for(int i = 1;i <= n; ++i)
if(fabs(c[i].x - x) <= c[i].r - eps) {
double dis = sqrt(sqr(c[i].r) - (x - c[i].x) * (x - c[i].x));
p[++tot].l = c[i].y - dis; p[tot].r = c[i].y + dis;
}
if(!tot) return 0;
sort(p + 1, p + tot + 1, cmp3);
double h = -2200;
for(int i = 1;i <= tot; ++i) {
if(p[i].l > h) ret += p[i].r - p[i].l, h = p[i].r;
else if(p[i].r > h) ret += p[i].r - h, h = p[i].r;
}
return ret;
}
double calc(double l, double r) {return (r - l) / 6 * (F(l) + 4 * F((l + r) / 2.0) + F(r)) ;}
double Simpson(double l, double r) {
double m = (l + r) / 2.0, s1 = calc(l, m) + calc(m, r), s2 = calc(l, r);
if(fabs(s1 - s2) < eps) return s1;
else return Simpson(l, m) + Simpson(m, r);
}
int main() {
n = read();
for(int i = 1;i <= n; ++i) {
c[i].x = read(); c[i].y = read(); c[i].r = read();
L = min(L, c[i].x - c[i].r); R = max(R, c[i].x + c[i].r);
}
Del();
printf("%.3lf\n", Simpson(-2000.0, 2000.0));
return 0;
}
/*
3
0 0 1
1 0 1
0 1 1
*/
对于插值型求积公式,在信息学中主要应用自适应辛普森积分算法。此算法的优点在于好写易懂,并有一定的精确度。但是对于某些“二分精度”题,还是小心为妙。