数值微分本质上就是通过离散点来对未知的函数方程进行微分的数值求解。
我们给出导数的基础定义如下:
f ′ ( x ) = l i m h → 0 f ( x + h ) − f ( x ) h f'(x) = lim_{h \to 0} \frac{f(x+h) - f(x)}{h} f′(x)=limh→0hf(x+h)−f(x)
因此,只要给出的离散点足够密集,我们就可以通过直接求解的方法进行微分的数值求解。
而关于其误差分析,我们有:
向前差商
R ( x ) = f ′ ( x ) − f ( x + h ) − f ( x ) h = − h 2 f ′ ′ ( ξ ) ∼ O ( h ) \begin{aligned} R(x) &= f'(x) - \frac{f(x+h) - f(x)}{h} \\ &= -\frac{h}{2}f''(\xi) \sim O(h) \end{aligned} R(x)=f′(x)−hf(x+h)−f(x)=−2hf′′(ξ)∼O(h)
向后差商
R ( x ) = f ′ ( x ) − f ( x ) − f ( x − h ) h = h 2 f ′ ′ ( ξ ) ∼ O ( h ) \begin{aligned} R(x) &= f'(x) - \frac{f(x) - f(x-h)}{h} \\ &= \frac{h}{2}f''(\xi) \sim O(h) \end{aligned} R(x)=f′(x)−hf(x)−f(x−h)=2hf′′(ξ)∼O(h)
中心差商
R ( x ) = f ′ ( x ) − f ( x + h ) − f ( x − h ) 2 h = h 2 6 f ′ ′ ′ ( ξ ) ∼ O ( h 2 ) \begin{aligned} R(x) &= f'(x) - \frac{f(x+h) - f(x-h)}{2h} \\ &= \frac{h^2}{6}f'''(\xi) \sim O(h^2) \end{aligned} R(x)=f′(x)−2hf(x+h)−f(x−h)=6h2f′′′(ξ)∼O(h2)
不过,如果离散点不够密集,那么使用上述方式进行的微分估计事实上会带来比较大的误差,因此,我们需要对其进行一下调整,此时一种比较直接的方式就是我们先用一个插值函数来对曲线进行拟合,然后再求取插值函数的微分结果作为目标函数的微分结果。
同样的,根据之前Lagrange插值函数的误差分析内容,我们即可快速得到插值型微分的误差分析:
R ( x i ) = Π j ≠ i ( x i − x j ) f ( n + 1 ) ( ξ ) ( n + 1 ) ! R(x_i) = \Pi_{j \neq i}(x_i - x_j) \frac{f^{(n+1)}(\xi)}{(n+1)!} R(xi)=Πj=i(xi−xj)(n+1)!f(n+1)(ξ)
插值型数值积分和上述插值型数值微分的思路是完全一致的,就是用插值函数来拟合未知曲线,然后用这个插值函数在对应空间上的积分值来近似未知函数的积分值。
亦即:
∫ a b f ( x ) d x ≃ ∫ a b L n ( x ) d x \int_{a}^{b}f(x)dx \simeq \int_{a}^{b}L_n(x)dx ∫abf(x)dx≃∫abLn(x)dx
显然,对于 n n n阶插值函数,数值积分的结果就有 n n n阶代数精度,即:
当目标函数的阶数不高于 n n n阶时,数值积分的结果没有误差。
Newton-Cotes积分算是插值型数值积分中的一个特例。
他是说在积分区间里面等分各个位置,然后用这些等分的位置上的函数值进行插值最后进行函数的求解。
梯形积分其实就是一阶的Newton-Cotes积分,其具体的结果可以表述为:
∫ a b f ( x ) d x = b − a 2 ⋅ ( f ( a ) + f ( b ) ) \int_{a}^{b}f(x)dx = \frac{b-a}{2} \cdot (f(a) + f(b)) ∫abf(x)dx=2b−a⋅(f(a)+f(b))
显然的,梯形积分具有一阶代数精度。
Simpson积分其实就是二阶的Newton-Cotes积分,具体而言,我们取区间范围的中值,然后进行二阶插接,然后用这个插值函数来计算积分的结果。
具体而言,我们有:
$$
L_2(x) = \frac{(x-\frac{a+b}{2})(x-b)}{(a-\frac{a+b}{2})(a-b)}f(a)
积分即有:
∫ a b L 2 ( x ) d x = b − a 6 [ f ( a ) + 4 f ( a + b 2 ) + f ( b ) ] \int_a^b L_2(x)dx = \frac{b-a}{6}[f(a) + 4f(\frac{a+b}{2}) + f(b)] ∫abL2(x)dx=6b−a[f(a)+4f(2a+b)+f(b)]
不过,比较特殊的是,Simpson公式具有三阶代数精度。
仿上,我们可以求解得到n阶的Newton-Cotes积分结果如下:
∫ a b L n ( x ) d x = ∑ i = 0 n α i f ( x i ) \int_a^bL_n(x)dx = \sum_{i=0}^n \alpha_i f(x_i) ∫abLn(x)dx=i=0∑nαif(xi)
其中,系数 α i \alpha_i αi可以进一步表示为:
α i = ( b − a ) ⋅ C i ( n ) \alpha_i = (b-a) \cdot C_i^{(n)} αi=(b−a)⋅Ci(n)
其中, C i ( n ) C_i^{(n)} Ci(n)称之为Newton-Cotes系数,其表达式可以展开为:
C i ( n ) = ( − 1 ) n − i i ! ( n − i ) ! n ∫ 0 n Π j = 0 , j ≠ i n ( t − j ) d t C_i^{(n)} = \frac{(-1)^{n-i}}{i!(n-i)!n}\int_{0}^{n}\Pi_{j=0, j \neq i}^{n} (t- j)dt Ci(n)=i!(n−i)!n(−1)n−i∫0nΠj=0,j=in(t−j)dt
而关于 n n n阶Newton-Cotes积分的的误差分析如下:
Newton-Cotes积分或者更一般的插值型数值积分本质上思路都是用一个拟合函数来对原始的未知函数或者复杂函数进行替换,然后用这个拟合函数的积分值来近似原本的函数的积分值。
而这里的复化数值积分思路则与上述有所不同,它更接近于积分原本的定义,就是直接先对积分区间进行分段,然后在每一个区间段内进行近似积分求解,最后将他们的总和作为最终的数值积分结果。
而具体到每一段区间的积分,则又可以回归到数值积分方法上面了。
复化梯形积分就是在每一个子区间上面使用梯形积分进行拟合。
我们可以快速地写出最终的积分结果如下:
∫ a b f ( x ) d x = ∑ i = 0 n − 1 h 2 [ f ( a + i h ) + f ( a + ( i + 1 ) h ) ] = h [ 1 2 f ( a ) + ∑ i = 1 n − 1 f ( a + i h ) + 1 2 f ( b ) ] \begin{aligned} \int_{a}^{b}f(x)dx &= \sum_{i=0}^{n-1}\frac{h}{2}[f(a+ih) + f(a+(i+1)h)] \\ &= h[\frac{1}{2}f(a) + \sum_{i=1}^{n-1}f(a+ih) + \frac{1}{2}f(b)] \end{aligned} ∫abf(x)dx=i=0∑n−12h[f(a+ih)+f(a+(i+1)h)]=h[21f(a)+i=1∑n−1f(a+ih)+21f(b)]
其误差可以表示为:
δ = − ( b − a ) 3 12 n 2 f ′ ′ ( ξ ) ∼ O ( 1 n 2 ) \delta = -\frac{(b-a)^3}{12n^2}f''(\xi) \sim O(\frac{1}{n^2}) δ=−12n2(b−a)3f′′(ξ)∼O(n21)
同样的,我们如果对每一个子区间使用Simpson积分公式进行拟合的话,就可以得到复化Simpson积分,其具体公式可以表达为:
∫ a b f ( x ) d x = ∑ i = 0 n − 1 2 h 6 [ f ( a + i h ) + 4 f ( a + ( i + 1 2 ) h ) + f ( a + ( i + 1 ) h ) ] = h 3 [ f ( a ) + 4 ∑ i = 0 n − 1 f ( a + ( i + 1 2 ) h ) + 2 ∑ i = 1 n − 1 f ( a + i h ) + f ( b ) ] \begin{aligned} \int_{a}^{b}f(x)dx &= \sum_{i=0}^{n-1} \frac{2h}{6}[f(a + ih) + 4f(a + (i+\frac{1}{2})h) + f(a + (i+1)h)] \\ &= \frac{h}{3}[f(a) + 4 \sum_{i=0}^{n-1}f(a + (i+\frac{1}{2})h) + 2 \sum_{i=1}^{n-1} f(a+ih) + f(b)] \end{aligned} ∫abf(x)dx=i=0∑n−162h[f(a+ih)+4f(a+(i+21)h)+f(a+(i+1)h)]=3h[f(a)+4i=0∑n−1f(a+(i+21)h)+2i=1∑n−1f(a+ih)+f(b)]
其误差可以表达为:
δ = − ( 2 h ) 5 2880 ∑ i = 0 n − 1 f ( 4 ) ( ξ i ) = − ( b − a ) 5 2880 n 4 f ( 4 ) ( ξ ) ∼ O ( 1 n 4 ) \begin{aligned} \delta &= -\frac{(2h)^5}{2880}\sum_{i=0}^{n-1}f^{(4)}(\xi_i) \\ &= -\frac{(b-a)^5}{2880n^4}f^{(4)}(\xi) \sim O(\frac{1}{n^4}) \end{aligned} δ=−2880(2h)5i=0∑n−1f(4)(ξi)=−2880n4(b−a)5f(4)(ξ)∼O(n41)
Romberg积分本质上和上述实现并无什么不同,无非就是在每一个子区间内使用更高阶的Newton-Cotes积分进行拟合。
我们给出一个Romberg积分 R n , k R_{n, k} Rn,k,其定义就是说将积分区间进行 2 n − 1 2^{n-1} 2n−1等分,然后对于每一个子区间,我们采用高阶的Newton-Cotes积分进行求解,具体而言,我们将其进一步分为 2 k − 1 2^{k-1} 2k−1个节点,然后计算Newton-Cotes积分。
显然,这就是在 k − 1 k-1 k−1阶的基础上对于每一个子区间再一次进行对半细分,因此,我们有迭代公式如下:
R n , k = R n , k − 1 + R n , k − 1 − R n − 1 , k − 1 4 k − 1 − 1 R_{n, k} = R_{n, k-1} + \frac{R_{n, k-1} - R_{n-1, k-1}}{4^{k-1}-1} Rn,k=Rn,k−1+4k−1−1Rn,k−1−Rn−1,k−1
我们可以将其进一步翻译成python伪代码如下:
def romberg_integrate(fn, a, b, n, k, epsilon=1e-6):
R = [[0 for _ in range(k)] for _ in range(n)]
R[0][0] = (fn(a) + fn(b)) / 2
h = b-a
for i in range(1, n):
residual = sum([fn(a + (j + 1/2) * h) for j in range(2**(i-1))])
R[i][0] = (R[i-1][0] + h * residual) / 2
for j in range(1, min(k, i+1)):
R[i][j] = R[i][j-1] + (R[i][j-1] - R[i-1][j-1]) / (4**j - 1)
if abs(R[i][j] - R[i][j-1]) < epsilon:
return R[i][j]
h = h / 2
return R[-1][-1]