R [ f ] = ∫ a b f ( x ) d x − ∑ k = 0 n A k f ( x k ) = K f ( m + 1 ) ( η ) , ( 1 ) R[f]=\int_a^b\!\!\!f(x)\mathrm{d}x-\sum_{k=0}^nA_kf(x_k)=Kf^{(m+1)}(\eta ),(1) R[f]=∫abf(x)dx−k=0∑nAkf(xk)=Kf(m+1)(η),(1)
其中 K 为不依赖 f ( x ) 的待定参数 , η ∈ ( a , b ) . 其中K为不依赖f(x)的待定参数,\eta \in (a,b). 其中K为不依赖f(x)的待定参数,η∈(a,b). 这个结果表明当 f ( x ) 是次数小于等于 m 的多项式时 , 这个结果表明当f(x)是次数小于等于m的多项式时, 这个结果表明当f(x)是次数小于等于m的多项式时,
由于 f ( m + 1 ) ( x ) = 0 , 故此时 R [ f ] = 0 , 即求积公式 ∫ a b f ( x ) d x ≈ ∑ k = 0 n A k f ( x k ) 由于f^{(m+1)}(x)=0,故此时R[f]=0,即求积公式\int_a^b\!f(x)\mathrm{d}x\approx\sum\limits_{k=0}^nA_kf(x_k) 由于f(m+1)(x)=0,故此时R[f]=0,即求积公式∫abf(x)dx≈k=0∑nAkf(xk)
精确成立 . 而当 f ( x ) = x m + 1 时 , f ( m + 1 ) ( x ) = ( m + 1 ) ! , ( 1 ) 式左端 R n ( f ) ≠ 0 , 故可求得 精确成立.而当f(x)=x^{m+1}时,f^{(m+1)}(x)=(m+1)!,(1)式左端R_n(f)\neq 0,故可求得 精确成立.而当f(x)=xm+1时,f(m+1)(x)=(m+1)!,(1)式左端Rn(f)=0,故可求得
K = 1 ( m + 1 ) ! [ ∫ a b x m + 1 d x − ∑ k = 0 n A k x m + 1 ] = 1 ( m + 1 ) ! [ 1 ( m + 2 ) ( b m + 2 − a m + 2 ) − ∑ k = 0 n A k x m + 1 ] \begin{aligned} K&=\frac{1}{(m+1)!}\left[\int_a^b\!\!\!x^{m+1}\mathrm{d}x-\sum_{k=0}^nA_kx^{m+1}\right]\\ &=\frac{1}{(m+1)!}\left[\frac{1}{(m+2)}(b^{m+2}-a^{m+2})-\sum_{k=0}^nA_kx^{m+1}\right] \end{aligned} K=(m+1)!1[∫abxm+1dx−k=0∑nAkxm+1]=(m+1)!1[(m+2)1(bm+2−am+2)−k=0∑nAkxm+1]
from sympy.abc import x
from sympy import integrate, exp, diff
import numpy as np
from math import factorial
def quadrature_reminder(a, b, equal_segment, m, intergrand, a_k: np.ndarray):
"""
实现[a,b]代数精度为m的求积公式余项表达式
:param a: 区间左端点即起点a
:param b: 区间右端点即终点b
:param equal_segment: 区间等分数n
:param m: 代数精度m
:param intergrand: 被积函数f(x)
:param a_k: 权系数Ak数组
:return: 求积公式余项表达式
"""
step_h = (b - a) / equal_segment
f_x = x ** (m + 1)
f_x_k_array = np.array([f_x.subs(x, a + k * step_h) for k in range(equal_segment + 1)])
return 1 / factorial(m + 1) * (1 / (m + 2) * (b ** (m + 2) - a ** (m + 2)) - np.sum(a_k * f_x_k_array)) * diff(
intergrand, x, m + 1), a, b
设将积分区间 [ a , b ] 分为 n 等分 , 步长 h = b − a n , 选取等距节点 x k = a + k h 设将积分区间[a,b]分为n等分,步长h=\dfrac{b-a}{n},选取等距节点x_k=a+kh 设将积分区间[a,b]分为n等分,步长h=nb−a,选取等距节点xk=a+kh 构造出的插值型求积公式 构造出的插值型求积公式 构造出的插值型求积公式
I n = ( b − a ) ∑ k = 0 n C k ( n ) f ( x k ) , I_n=(b-a)\sum_{k=0}^nC_k^{(n)}f(x_k), In=(b−a)k=0∑nCk(n)f(xk),
称为 牛顿-柯特斯 ( N e w t o w n − C o t e s ) 公式 , 式中 C k ( n ) 称为 柯特斯系数 . 称为\textbf{牛顿-柯特斯}(\mathrm{Newtown-Cotes})\textbf{公式},式中C_k^{(n)}称为\textbf{柯特斯系数}. 称为牛顿-柯特斯(Newtown−Cotes)公式,式中Ck(n)称为柯特斯系数.
根据求积系数 A k = ∫ a b l k ( x ) d x , k = 0 , 1 , … , n . 引进变换 x = a + t h , 则有 根据求积系数A_k=\int_a^bl_k(x)\mathrm{d}x,k=0,1,\ldots,n.引进变换x=a+th,则有 根据求积系数Ak=∫ablk(x)dx,k=0,1,…,n.引进变换x=a+th,则有
C k ( n ) = h b − a ∫ 0 n ∏ j = 0 j ≠ k n t − j k − j d t = ( − 1 ) n − k n k ! ( n − k ) ! ∫ 0 n ∏ j = 0 j ≠ k n ( t − j ) d t . C_k^{(n)}=\frac{h}{b-a}\int_0^n\prod_{j=0\\j\neq k}^n\frac{t-j}{k-j}\mathrm{d}t=\frac{(-1)^{n-k}}{nk!(n-k)!}\int_0^n\prod_{j=0\\j\neq k}^n(t-j)\mathrm{d}t. Ck(n)=b−ah∫0nj=0j=k∏nk−jt−jdt=nk!(n−k)!(−1)n−k∫0nj=0j=k∏n(t−j)dt.
特别地,当 n = 2 时 , 相应的求积公式称为 辛普森 ( S i m p s o n ) 公式 : 特别地,当n=2时,相应的求积公式称为\textbf{辛普森}(\mathrm{Simpson})\textbf{公式}: 特别地,当n=2时,相应的求积公式称为辛普森(Simpson)公式:
S = b − a 6 [ f ( a ) + 4 f ( a + b 2 ) + f ( b ) ] . S=\frac{b-a}{6}\left[f(a)+4f(\frac{a+b}{2})+f(b)\right]. S=6b−a[f(a)+4f(2a+b)+f(b)].
def newtown_cotes_integrate(equal_segment, interval_start, interval_end, symbol_t, f_x):
"""
实现牛顿-柯特斯(Newton-Cotes)插值型积分
:param symbol_t: 引进变换x=a+t*h后的积分变量
:param equal_segment: 区间等分数n
:param interval_start: 区间左端点即起点
:param interval_end: 区间右端点即终点
:param f_x: 被积函数 intergrand
:return:牛顿-柯特斯(Newton-Cotes)插值积分
"""
step_h = (interval_end - interval_start) / equal_segment
f_k_array = np.array([f_x.subs(x, interval_start + k * step_h) for k in range(equal_segment + 1)])
return (interval_end - interval_start) * np.sum(cotes_coefficient(equal_segment, symbol_t) * f_k_array)
def cotes_coefficient(equal_segment, symbol_t):
"""
实现牛顿-柯特斯(Newton-Cotes)插值型求积公式的柯特斯系数
:param equal_segment: 区间等分数n,其中1<=n<=7,n>7的牛顿-柯特斯公式计算不稳定,不使用.
:param symbol_t: 引进变换x=a+t*h后的积分变量t
:return: 柯特斯系数数组
"""
if equal_segment not in range(1, 8):
raise ValueError("Cotes coefficient must be an integer between 1 and 7")
c_k_array = np.zeros(equal_segment + 1, dtype=np.float64)
for k in range(equal_segment + 1):
index = list(range(equal_segment + 1))
index.pop(k)
intergrand = np.prod(symbol_t - np.array(index))
integral = integrate(intergrand, (symbol_t, 0, equal_segment))
c_k_array[k] = (-1) ** (equal_segment - k) / (
equal_segment * factorial(k) * factorial(equal_segment - k)) * integral
return c_k_array
将区间 [ a , b ] 划分为 n 等份 , 分点 x k = a + k h , h = b − a n , k = 0 , 1 , … , n , 将区间[a,b]划分为n等份,分点x_k=a+kh,h=\dfrac{b-a}{n},k=0,1,\ldots,n, 将区间[a,b]划分为n等份,分点xk=a+kh,h=nb−a,k=0,1,…,n, 在每个子区间 [ x k , x k + 1 ] ( k = 0 , 1 , … , n − 1 ) 上 在每个子区间[x_k,x_{k+1}](k=0,1,\ldots,n-1)上 在每个子区间[xk,xk+1](k=0,1,…,n−1)上
采用梯形公式 ∫ a b f ( x ) d x ≈ b − a 2 [ f ( a ) + f ( b ) ] , 则得 采用梯形公式\int_a^b\!f(x)\mathrm{d}x\approx\dfrac{b-a}{2}[f(a)+f(b)],则得 采用梯形公式∫abf(x)dx≈2b−a[f(a)+f(b)],则得
T n = h 2 ∑ k = 0 n − 1 [ f ( x k ) + f ( x k + 1 ) ] = h 2 [ f ( a ) + 2 ∑ k = 1 n − 1 f ( x k ) + f ( b ) ] , T_n=\frac{h}{2}\sum_{k=0}^{n-1}[f(x_k)+f(x_{k+1})]=\frac{h}{2}\left[f(a)+2\sum_{k=1}^{n-1}f(x_k)+f(b)\right], Tn=2hk=0∑n−1[f(xk)+f(xk+1)]=2h[f(a)+2k=1∑n−1f(xk)+f(b)],
称为复合梯形公式
def com_trapz(a, b, equal_segment, intergrand):
"""
实现复合梯形求积公式
:param a: 区间左端点即起点a
:param b: 区间右端点即终点b
:param equal_segment: 区间等分数n
:param intergrand: 被积函数f(x)
:return: 复合梯形求积积分
"""
step_h = (b - a) / equal_segment
f_x_k_array = np.array([intergrand.subs(x, a + k * step_h) for k in range(1, equal_segment)])
return step_h / 2 * (intergrand.subs(x, a) + 2 * np.sum(f_x_k_array) + intergrand.subs(x, b))
将区间 [ a , b ] 划分为 n 等份 , 在每个子区间 [ x k , x k + 1 ] ( k = 0 , 1 , … , n − 1 ) 上 将区间[a,b]划分为n等份,在每个子区间[x_k,x_{k+1}](k=0,1,\ldots,n-1)上 将区间[a,b]划分为n等份,在每个子区间[xk,xk+1](k=0,1,…,n−1)上
采用辛普森公式 , 若记 x k + 1 / 2 = x k + 1 2 h , 则得 采用辛普森公式,若记x_{k+1/2}=x_k+\frac{1}{2}h,则得 采用辛普森公式,若记xk+1/2=xk+21h,则得
S n = h 6 ∑ k = 0 n − 1 [ f ( x k ) + 4 f ( x k + 1 / 2 ) + f ( x k + 1 ) ] = h 6 [ f ( a ) + 4 ∑ k = 0 n − 1 f ( x k + 1 / 2 ) + 2 ∑ k = 1 n − 1 f ( x k ) + f ( b ) ] , \begin{aligned} S_n&=\frac{h}{6}\sum_{k=0}^{n-1}[f(x_k)+4f(x_{k+1/2})+f(x_{k+1})]\\ &=\frac{h}{6}\left[f(a)+4\sum_{k=0}^{n-1}f(x_{k+1/2})+2\sum_{k=1}^{n-1}f(x_k)+f(b)\right], \end{aligned} Sn=6hk=0∑n−1[f(xk)+4f(xk+1/2)+f(xk+1)]=6h[f(a)+4k=0∑n−1f(xk+1/2)+2k=1∑n−1f(xk)+f(b)],
称为复合辛普森公式
def com_simpson(a, b, equal_segment, intergrand):
"""
实现复合辛普森求积公式
:param a: 区间左端点即起点a
:param b: 区间右端点即终点b
:param equal_segment: 区间等分数n
:param intergrand: 被积函数f(x)
:return: 复合辛普森求积积分
"""
step_h = (b - a) / equal_segment
f_x_k1_array = np.array([intergrand.subs(x, a + (k+0.5) * step_h) for k in range(equal_segment)],
dtype=np.float64)
f_x_k2_array = np.array([intergrand.subs(x, a + k * step_h) for k in range(1, equal_segment)],
dtype=np.float64)
return step_h / 6 * (
intergrand.subs(x, a) + 4 * np.sum(f_x_k1_array) + 2 * np.sum(f_x_k2_array) + intergrand.subs(x, b))
if __name__ == '__main__':
# 辛普森公式及其余项表达式测试成功,来源详见来源详见李庆扬数值分析第5版P135,e.g.4
# 0.632333680003663
inter_grand = exp(-x)
print("辛普森公式积分为:{}".format(newtown_cotes_integrate(2, 0, 1, x, inter_grand)))
print("辛普森公式为:{}".format(quadrature_reminder(a=0, b=1, equal_segment=2, m=3, intergrand=exp(-x), a_k=cotes_coefficient(2, x))[0]))
# 复合梯形公式和复合辛普森公式测试成功,来源详见来源详见李庆扬数值分析第5版P135,e.g.2(1)
f_x = x / (4 + x ** 2)
print("复合梯形公式积分:{}".format(com_trapz(a=0, b=1, equal_segment=8, intergrand=f_x))) # 0.111402354529548
print("复合辛普森公式积分:{}".format(com_simpson(a=0, b=1, equal_segment=8, intergrand=f_x))) # 0.111571813252631