函数插值的python实现——拉格朗日、牛顿插值

1. 拉格朗日(Larange)插值

\qquad 拉格朗日插值,是通过构造 n + 1 n+1 n+1 个插值节点来构造 n n n 阶插值多项式。

\qquad 假设 n + 1 n+1 n+1 个插值节点为 x 0 , x 1 , ⋯   , x n x_0,x_1,\cdots,x_n x0,x1,,xn,且满足函数插值条件:

L n ( x k ) = f ( x k ) = f k   , k = 0 , 1 , ⋯   , n \qquad\qquad L_n(x_k)=f(x_k)=f_k\ ,\quad k=0,1,\cdots,n Ln(xk)=f(xk)=fk ,k=0,1,,n

\qquad
\qquad 拉格朗日插值的 n n n 阶插值基函数为:

l k ( x ) = ( x − x 0 ) ⋯ ( x − x k − 1 ) ( x − x k + 1 ) ⋯ ( x − x n ) ( x k − x 0 ) ⋯ ( x k − x k − 1 ) ( x k − x k + 1 ) ⋯ ( x k − x n ) \qquad\qquad l_k(x)=\dfrac{(x-x_0)\cdots(x-x_{k-1})(x-x_{k+1})\cdots(x-x_n)}{(x_k-x_0)\cdots(x_k-x_{k-1})(x_k-x_{k+1})\cdots(x_k-x_n)} lk(x)=(xkx0)(xkxk1)(xkxk+1)(xkxn)(xx0)(xxk1)(xxk+1)(xxn)

\qquad
\qquad 显然,对于任意的插值节点 x i x_i xi,插值基函数满足:

l k ( x i ) = {   1 , x i = x k   0 , x i ≠ x k \qquad\qquad l_k(x_i)=\left\{\begin{aligned}\ 1,\qquad x_i=x_k\\ \\ \ 0,\qquad x_i\ne x_k\end{aligned}\right. lk(xi)=  1,xi=xk 0,xi=xk

\qquad 因此, n n n 阶拉格朗日插值多项式就可以写为: L n ( x ) = ∑ k = 0 n f k l k ( x ) L_n(x)=\displaystyle\sum_{k=0}^nf_kl_k(x) Ln(x)=k=0nfklk(x)

假设 f ( n ) ( x ) f^{(n)}(x) f(n)(x) [ a , b ] [a,b] [a,b] 上连续, f ( n + 1 ) ( x ) f^{(n+1)}(x) f(n+1)(x) ( a , b ) (a,b) (a,b) 上存在
假设 n + 1 n+1 n+1 个插值节点 a ≤ x 0 < x 1 < ⋯ < x n ≤ b a\le x_0<x_1<\cdots<x_n\le b ax0<x1<<xnb
n + 1 n+1 n+1 阶多项式 ω n + 1 ( x ) = ( x − x 0 ) ( x − x 1 ) ⋯ ( x − x n ) \omega_{n+1}(x)=(x-x_0)(x-x_1)\cdots(x-x_{n}) ωn+1(x)=(xx0)(xx1)(xxn)
插值余项
     R n ( x ) = f ( x ) − L n ( x ) = f ( n + 1 ) ( ξ ) ( n + 1 ) ! ω n + 1 ( x ) , ξ ∈ ( a , b ) ,   ∀ x ∈ [ a , b ] R_n(x)=f(x)-L_n(x)=\dfrac{f^{(n+1)}(\xi)}{(n+1)!}\omega_{n+1}(x),\quad\xi\in(a,b),\ \forall x\in[a,b] Rn(x)=f(x)Ln(x)=(n+1)!f(n+1)(ξ)ωn+1(x),ξ(a,b), x[a,b]

\qquad

实现代码

import numpy as np
import matplotlib.pyplot as plt

def intLagrange(x,xcp,f):
    hatf = np.zeros(len(x))
    for n in range(len(x)):
        for k in range(len(xcp)):
            xcp1 = xcp.copy()
            xcp1[k] = xcp[k] - 1
            xcp2 = xcp.copy()
            xcp2[k] = x[n] - 1
            hatf[n] += f(xcp[k])*np.prod(x[n]-xcp2)/np.prod(xcp[k]-xcp1)
    return hatf

if __name__ == '__main__':    
    plt.figure(figsize=(7, 4))    
    # parameters
    cpnum = 17      # 插值节点数
    xs = -9
    xe = 11
    x = np.arange(xs,xe,0.1)    #待插值点
    xcp = np.linspace(xs,xe,cpnum)    
    # function to be interpolated
    f = lambda x: x**2 + 30*np.sin(x)  
    plt.plot(x,f(x))    
    # Lagrange    
    hatf = intLagrange(x,xcp,f)        
    plt.plot(x,hatf)        
    # plot control point
    for i in range(len(xcp)):    
        plt.plot(xcp[i],f(xcp[i]),'ro',markerfacecolor='none')        
    plt.legend(['original','Lagrange','control point'])
    plt.title('Lagrange Interpolation')
    plt.show()

运行结果
\qquad 在这里插入图片描述

拉格朗日插值法的主要缺点:一旦插值节点的数量 n n n 发生改变,所有的插值基函数 l k ( x ) ,   k = 0 , 1 , ⋯   , n l_k(x),\ k=0,1,\cdots,n lk(x), k=0,1,,n 都需要重新计算。

\qquad

2. 牛顿(Larange)插值

2.1 牛顿插值多项式的基本形式

\qquad 拉格朗日插值法的主要缺点:一旦插值节点的数量 n n n 发生改变,所有的插值基函数 l k ( x ) ,   k = 0 , 1 , ⋯   , n l_k(x),\ k=0,1,\cdots,n lk(x), k=0,1,,n 都需要重新计算。

\qquad 牛顿插值法可以克服这一缺点, n n n 阶牛顿插值多项式的形式为:

P n ( x ) = a 0 + a 1 ( x − x 0 ) + a 2 ( x − x 0 ) ( x − x 1 ) + ⋯ + a n ( x − x 0 ) ( x − x 1 ) ⋯ ( x − x n − 1 ) \qquad\qquad P_n(x)=a_0+a_1(x-x_0)+a_2(x-x_0)(x-x_1)+\cdots+a_n(x-x_0)(x-x_1)\cdots(x-x_{n-1}) Pn(x)=a0+a1(xx0)+a2(xx0)(xx1)++an(xx0)(xx1)(xxn1)

显然, n n n 阶牛顿插值多项式 P n ( x ) P_n(x) Pn(x) 只与 n n n 个插值节点 x 0 , x 1 , ⋯   , x n − 1 x_0,x_1,\cdots,x_{n-1} x0,x1,,xn1 有关。

\qquad
\qquad 如果增加一个新的插值节点 x n x_n xn,那么新的 n + 1 n+1 n+1 阶牛顿插值多项式 P n + 1 ( x ) P_{n+1}(x) Pn+1(x) 只需要在 P n ( x ) P_n(x) Pn(x) 后再增加一项:

P n + 1 ( x ) = P n ( x ) + \qquad\qquad P_{n+1}(x)=P_n(x)+ Pn+1(x)=Pn(x)+   a n + 1 ( x − x 0 ) ( x − x 1 ) ⋯ ( x − x n − 1 ) ( x − x n ) \ a_{n+1}(x-x_0)(x-x_1)\cdots(x-x_{n-1})(x-x_n)  an+1(xx0)(xx1)(xxn1)(xxn)

\qquad
\qquad 对于 n n n 阶牛顿插值多项式 P n ( x ) P_n(x) Pn(x),需要求出 n n n 个插值系数 a 0 , a 1 , ⋯   , a n − 1 a_0,a_1,\cdots,a_{n-1} a0,a1,,an1,并且满足函数插值条件:

P n ( x i ) = f ( x i ) , i = 0 , 1 , ⋯   , n − 1 \qquad\qquad P_n(x_i)=f(x_i),\quad i=0,1,\cdots,n-1 Pn(xi)=f(xi),i=0,1,,n1
\qquad

2.2 牛顿均差插值多项式

\qquad 将某个插值节点 x k x_k xk 的函数值记为 f k = f ( x k ) f_k=f(x_k) fk=f(xk),已知区间 [ x 0 , x n − 1 ] [x_0,x_{n-1}] [x0,xn1] 上的 n n n 个插值节点 x 0 , x 1 , ⋯   , x n − 1 x_0,x_1,\cdots,x_{n-1} x0,x1,,xn1 的函数值 f 0 , f 1 , ⋯   , f n − 1 f_0,f_1,\cdots,f_{n-1} f0,f1,,fn1

\qquad 分析牛顿插值多项式:

P n ( x ) = a 0 + a 1 ( x − x 0 ) + a 2 ( x − x 0 ) ( x − x 1 ) + ⋯ + a n ( x − x 0 ) ( x − x 1 ) ⋯ ( x − x n − 1 ) \qquad\qquad P_n(x)=a_0+a_1(x-x_0)+a_2(x-x_0)(x-x_1)+\cdots+a_n(x-x_0)(x-x_1)\cdots(x-x_{n-1}) Pn(x)=a0+a1(xx0)+a2(xx0)(xx1)++an(xx0)(xx1)(xxn1)

\qquad 可以依次求出牛顿插值多项式的各个系数:

( 1 ) \qquad(1) (1) x = x 0 x=x_0 x=x0 时, P n ( x 0 ) = a 0 = f 0 P_n(x_0)=a_0=f_0 Pn(x0)=a0=f0
⟹ a 0 = f 0 \qquad\newline\qquad\qquad\qquad\qquad\qquad\qquad\Longrightarrow a_0=f_0 a0=f0

( 2 ) \qquad(2) (2) x = x 1 x=x_1 x=x1 时, P n ( x 1 ) = a 0 + a 1 ( x 1 − x 0 ) = f 1 P_n(x_1)=a_0+a_1(x_1-x_0)=f_1 Pn(x1)=a0+a1(x1x0)=f1
⟹ a 1 = f 1 − f 0 x 1 − x 0 \qquad\newline\qquad\qquad\qquad\qquad\qquad\qquad\Longrightarrow a_1=\dfrac{f_1-f_0}{x_1-x_0} a1=x1x0f1f0

( 3 ) \qquad(3) (3) x = x 2 x=x_2 x=x2 时, P n ( x 2 ) = a 0 + a 1 ( x 2 − x 0 ) + a 2 ( x 2 − x 0 ) ( x 2 − x 1 ) = f 2 P_n(x_2)=a_0+a_1(x_2-x_0)+a_2(x_2-x_0)(x_2-x_1)=f_2 Pn(x2)=a0+a1(x2x0)+a2(x2x0)(x2x1)=f2
⟹ a 2 = f 2 − f 0 x 2 − x 0 − f 1 − f 0 x 1 − x 0 x 2 − x 1 \qquad\newline\qquad\qquad\qquad\qquad\qquad\qquad\Longrightarrow a_2=\dfrac{\dfrac{f_2-f_0}{x_2-x_0}-\dfrac{f_1-f_0}{x_1-x_0}}{x_2-x_1} a2=x2x1x2x0f2f0x1x0f1f0

\qquad
( 4 ) \qquad(4) (4) 依次递推,可以求出其余系数 a 3 , ⋯   , a n − 1 a_3,\cdots,a_{n-1} a3,,an1
\qquad

(1) 均差的定义

\qquad 定义一阶均差 f [ x 0 , x k ] = f ( x k ) − f ( x 0 ) x k − x 0 f[x_0,x_k]=\dfrac{f(x_k)-f(x_0)}{x_k-x_0} f[x0,xk]=xkx0f(xk)f(x0)

\qquad   二阶均差 f [ x 0 , x 1 , x k ] = f [ x 0 , x k ] − f [ x 0 , x 1 ] x k − x 1 f[x_0,x_1,x_k]=\dfrac{f[x_0,x_k]-f[x_0,x_1]}{x_k-x_1} f[x0,x1,xk]=xkx1f[x0,xk]f[x0,x1]

\qquad 以及k阶均差

f [ x 0 , x 1 , ⋯   , x k ] = f [ x 0 , ⋯   , x k − 2 , x k ] − f [ x 0 , x 1 , ⋯   , x k − 1 ] x k − x k − 1 \qquad\qquad f[x_0,x_1,\cdots,x_k]=\dfrac{f[x_0,\cdots,x_{k-2},x_k]-f[x_0,x_1,\cdots,x_{k-1}]}{x_k-x_{k-1}} f[x0,x1,,xk]=xkxk1f[x0,,xk2,xk]f[x0,x1,,xk1]

引入均差之后,显然 a 0 = f ( x 0 ) ,   a 1 = f [ x 0 , x 1 ] ,   a 2 = f [ x 0 , x 1 , x 2 ] ,   ⋯ a_0=f(x_0),\ a_1=f[x_0,x_1],\ a_2=f[x_0,x_1,x_2],\ \cdots a0=f(x0), a1=f[x0,x1], a2=f[x0,x1,x2], 

\qquad 那么 n n n 阶牛顿插值多项式就可以写为:

N n ( x ) = f ( x 0 ) + f [ x 0 , x 1 ] ( x − x 0 ) + f [ x 0 , x 1 , x 2 ] ( x − x 0 ) ( x − x 1 ) + ⋯ + f [ x 0 , x 1 , ⋯   , x n ] ( x − x 0 ) ( x − x 1 ) ⋯ ( x − x n − 1 ) \qquad\qquad\begin{aligned}N_n(x)&=f(x_0)+f[x_0,x_1](x-x_0)+f[x_0,x_1,x_2](x-x_0)(x-x_1)\\ &\quad+\cdots+f[x_0,x_1,\cdots,x_n](x-x_0)(x-x_1)\cdots(x-x_{n-1})\end{aligned} Nn(x)=f(x0)+f[x0,x1](xx0)+f[x0,x1,x2](xx0)(xx1)++f[x0,x1,,xn](xx0)(xx1)(xxn1)

\qquad

(2) 均差表

\qquad 为了简化计算,可根据均差的对称性(均差节点的排列次序无关),将 k k k 阶均差的表达式写为:

f [ x 0 , x 1 , ⋯   , x k ] = f [ x 1 , x 2 , ⋯   , x k ] − f [ x 0 , x 1 , ⋯   , x k − 1 ] x k − x 0 \qquad\qquad f[x_0,x_1,\cdots,x_k]=\dfrac{f[x_1,x_2,\cdots,x_k]-f[x_0,x_1,\cdots,x_{k-1}]}{x_k-x_0} f[x0,x1,,xk]=xkx0f[x1,x2,,xk]f[x0,x1,,xk1]

\qquad 根据该公式,就可以将 n n n 阶牛顿插值多项式的插值系数 a 0 , a 1 , ⋯   , a n − 1 a_0,a_1,\cdots,a_{n-1} a0,a1,,an1 的求解过程列成均差表

x k x_k xk f ( x k ) f(x_k) f(xk)一阶均差二阶均差三阶均差
x 0 x_0 x0 f ( x 0 ) ‾ \underline{f(x_0)} f(x0)
x 1 x_1 x1 f ( x 1 ) f(x_1) f(x1) f [ x 0 , x 1 ] ‾ \underline{f[x_0,x_1]} f[x0,x1]
x 2 x_2 x2 f ( x 2 ) f(x_2) f(x2) f [ x 1 , x 2 ] f[x_1,x_2] f[x1,x2] f [ x 0 , x 1 , x 2 ] ‾ \underline{f[x_0,x_1,x_2]} f[x0,x1,x2]
x 3 x_3 x3 f ( x 3 ) f(x_3) f(x3) f [ x 2 , x 3 ] f[x_2,x_3] f[x2,x3] f [ x 1 , x 2 , x 3 ] f[x_1,x_2,x_3] f[x1,x2,x3] f [ x 0 , x 1 , x 2 , x 3 ] ‾ \underline{f[x_0,x_1,x_2,x_3]} f[x0,x1,x2,x3]
⋮ \vdots ⋮ \vdots ⋮ \vdots ⋮ \vdots ⋮ \vdots

在均差表中,根据 k k k 阶均差公式,下划线标记的均差,均可由左侧的 2 2 2 个(左、左上)表格项求出。

\qquad
\qquad 若记 n n n 阶多项式 ω n ( x ) = ( x − x 0 ) ( x − x 1 ) ⋯ ( x − x n − 1 ) ,   n ≥ 1 \omega_n(x)=(x-x_0)(x-x_1)\cdots(x-x_{n-1}),\ n\ge1 ωn(x)=(xx0)(xx1)(xxn1), n1 ,那么 n n n 阶牛顿插值多项式又可表示为:

N n ( x ) = f ( x 0 ) + f [ x 0 , x 1 ] ω 1 ( x ) + f [ x 0 , x 1 , x 2 ] ω 2 ( x ) + ⋯ + f [ x 0 , x 1 , ⋯   , x n ] ω n ( x ) \qquad\qquad\begin{aligned}N_n(x)&=f(x_0)+f[x_0,x_1]\omega_1(x)+f[x_0,x_1,x_2]\omega_2(x)+\cdots+f[x_0,x_1,\cdots,x_n]\omega_n(x)\end{aligned} Nn(x)=f(x0)+f[x0,x1]ω1(x)+f[x0,x1,x2]ω2(x)++f[x0,x1,,xn]ωn(x)

实现代码

import numpy as np
import matplotlib.pyplot as plt

def intNewton(x,xcp,f):
    divdiff = getdivideddiff(xcp,f)
    hatf = np.ones(len(x))*f(xcp[0])
    for n in range(len(x)):
        t0 = 1
        for k in range(len(xcp)-1):
            # Newton
            t0 = (x[n]-xcp[k])*t0
            hatf[n] += divdiff[k]*t0
    return hatf

def getdivideddiff(xcp,f):
    divdiff = np.zeros(len(xcp)-1)
    t = f(xcp)
    for k in range(len(xcp)-1):
        num0 = t        
        num1 = np.concatenate((np.ones(1),num0[0:-1]))    
        k0 = k+1
        den = np.concatenate((np.ones(k0),xcp[0:-k0]))
        t = (num0-num1)/(xcp-den)
        divdiff[k] = t[k0]
    return divdiff

if __name__ == '__main__':    
    plt.figure(figsize=(7, 4))    
    # parameters
    cpnum = 17                          # 插值节点数
    xs = -9
    xe = 11
    x = np.linspace(xs,xe,100)          # 待插值点
    xcp = np.linspace(xs,xe,cpnum)      # 插值节点的函数值已知
    # function to be interpolated
    f = lambda x: x**2 + 30*np.sin(x) 
    plt.plot(x,f(x))        
    ##Newton Interpolation  
    hatf = intNewton(x,xcp,f)        
    plt.plot(x,hatf)        
    # plot control point
    for i in range(len(xcp)):    
        plt.plot(xcp[i],f(xcp[i]),'ro',markerfacecolor='none')        
    plt.legend(['original','Newton','control point'])
    plt.title('Newton Interpolation')    
    plt.show()

运行结果
\qquad 在这里插入图片描述

函数插值的结果,与插值节点的选择有关。为了方便,此处使用了等距插值节点。

\qquad

3. 等距插值节点的牛顿插值

(1) 差分的定义

\qquad 考虑“插值节点之间距离相等”的情况,也就是 x k = x 0 + k h , k = 0 , 1 , ⋯   , n x_k=x_0+kh,k=0,1,\cdots,n xk=x0+kh,k=0,1,,n,并记 f k = f ( x k ) f_k=f(x_k) fk=f(xk),可定义

1 ) \qquad1) 1) 一阶差分 { Δ f k = f k + 1 − f k 前向 ∇ f k = f k − f k − 1 后向 \left\{\begin{aligned}\Delta f_k=f_{k+1}-f_k \qquad 前向\\ \\ \nabla f_k=f_k-f_{k-1} \qquad 后向\end{aligned}\right. Δfk=fk+1fk前向fk=fkfk1后向

2 ) \qquad2) 2) 二阶差分 { Δ 2 f k = Δ f k + 1 − Δ f k 前向 ∇ 2 f k = Δ f k − Δ f k − 1 后向 \left\{\begin{aligned}\Delta^2 f_k=\Delta f_{k+1}-\Delta f_k \qquad 前向\\ \\ \nabla^2 f_k=\Delta f_k-\Delta f_{k-1} \qquad 后向\end{aligned}\right. Δ2fk=Δfk+1Δfk前向2fk=ΔfkΔfk1后向

\qquad 以及

3 ) \qquad3) 3) m \textbf{m} m阶差分 { Δ m f k = Δ m − 1 f k + 1 − Δ m − 1 f k 前向 ∇ m f k = Δ m − 1 f k − Δ m − 1 f k − 1 后向 \left\{\begin{aligned}\Delta^m f_k=\Delta^{m-1} f_{k+1}-\Delta^{m-1} f_k \qquad 前向\\ \\ \nabla^m f_k=\Delta^{m-1} f_k-\Delta^{m-1} f_{k-1} \qquad 后向\end{aligned}\right. Δmfk=Δm1fk+1Δm1fk前向mfk=Δm1fkΔm1fk1后向

\qquad
\qquad 从而,可得到均差差分之间的关系:

\qquad\qquad 一阶 f [ x k , x k + 1 ] = f k + 1 − f k x k + 1 − x k = Δ f k h f[x_k,x_{k+1}]=\dfrac{f_{k+1}-f_k}{x_{k+1}-x_k}=\dfrac{\Delta f_k}{h} f[xk,xk+1]=xk+1xkfk+1fk=hΔfk

\qquad\qquad 二阶 f [ x k , x k + 1 , x k + 2 ] = f [ x k + 1 , x k + 2 ] − f [ x k , x k + 1 ] x k + 2 − x k = Δ 2 f k 2 h 2 f[x_k,x_{k+1},x_{k+2}]=\dfrac{f[x_{k+1},x_{k+2}]-f[x_k,x_{k+1}]}{x_{k+2}-x_k}=\dfrac{\Delta^2 f_k}{2h^2} f[xk,xk+1,xk+2]=xk+2xkf[xk+1,xk+2]f[xk,xk+1]=2h2Δ2fk

⟹ \qquad\qquad\Longrightarrow\quad m \textbf{m} m f [ x k , x k + 1 , ⋯   , x k + m ] = Δ m f k m ! h m f[x_k,x_{k+1},\cdots,x_{k+m}]=\dfrac{\Delta^m f_k}{m!h^m} f[xk,xk+1,,xk+m]=m!hmΔmfk
\qquad

(2) 差分表

\qquad 等距插值节点的牛顿插值不再采用均差,而是采用差分。因此, n n n 阶牛顿插值多项式的插值系数 a 0 , a 1 , ⋯   , a n − 1 a_0,a_1,\cdots,a_{n-1} a0,a1,,an1 的求解过程可以列成差分表(以 n = 4 n=4 n=4 为例):

x k x_k xk f k f_k fk Δ ( ∇ ) \Delta(\nabla) Δ() Δ 2 ( ∇ 2 ) \Delta^2(\nabla^2) Δ2(2) Δ 3 ( ∇ 3 ) \Delta^3(\nabla^3) Δ3(3) Δ 4 ( ∇ 4 ) \Delta^4(\nabla^4) Δ4(4)
x 0 x_0 x0 f 0 f_0 f0
x 1 x_1 x1 f 1 f_1 f1 Δ f 0 ‾ ( ∇ f 1 ) \underline{\Delta f_0}(\nabla f_1) Δf0(f1)
x 2 x_2 x2 f 2 f_2 f2 Δ f 1 ( ∇ f 2 ) \Delta f_1(\nabla f_2) Δf1(f2) Δ 2 f 0 ‾ ( ∇ 2 f 2 ) \underline{\Delta^2f_0}(\nabla^2f_2) Δ2f0(2f2)
x 3 x_3 x3 f 3 f_3 f3 Δ f 2 ( ∇ f 3 ) \Delta f_2(\nabla f_3) Δf2(f3) Δ 2 f 1 ( ∇ 2 f 3 ) \Delta^2f_1(\nabla^2f_3) Δ2f1(2f3) Δ 3 f 0 ‾ ( ∇ 3 f 3 ) \underline{\Delta^3f_0}(\nabla^3f_3) Δ3f0(3f3)
x 4 x_4 x4 f 4 f_4 f4 Δ f 3 ( ∇ f 4 ‾ ‾ ) \Delta f_3(\underline{\underline{\nabla f_4}}) Δf3(f4) Δ 2 f 2 ( ∇ 2 f 4 ‾ ‾ ) \Delta^2f_2(\underline{\underline{\nabla^2f_4}}) Δ2f2(2f4) Δ 3 f 1 ( ∇ 3 f 4 ‾ ‾ ) \Delta^3f_1(\underline{\underline{\nabla^3f_4}}) Δ3f1(3f4) Δ 4 f 0 ‾ ( ∇ 4 f 4 ‾ ‾ ) \underline{\Delta^4f_0}(\underline{\underline{\nabla^4f_4}}) Δ4f0(4f4)

在差分表中,单下划线标记的前向差分、双下划线标记的后向差分,均可由左侧的 2 2 2 个(左、左上)表格项求出,下标正好相差一位。

\qquad

(3) 前向插值

\qquad 前向插值,是从区间 [ x 0 , x n − 1 ] [x_0,x_{n-1}] [x0,xn1] 的起点 x 0 x_0 x0 开始进行插值,任意待插值点的形式可写为 x = x 0 + t h ,   t ≥ 0 x=x_0+th,\ t\ge0 x=x0+th, t0

\qquad 牛顿插值多项式中的 n n n 阶多项式 ω n ( x ) \omega_n(x) ωn(x) 可以写为:

ω n ( x ) = ( x − x 0 ) ( x − x 1 ) ⋯ ( x − x n − 1 ) = t ( t − 1 ) ⋯ ( t − n + 1 ) h n ,   t ≥ 0 \qquad\qquad\omega_n(x)=(x-x_0)(x-x_1)\cdots(x-x_{n-1})=t(t-1)\cdots(t-n+1)h^n,\ t\ge0 ωn(x)=(xx0)(xx1)(xxn1)=t(t1)(tn+1)hn, t0

\qquad
\qquad 等距插值节点时的 n n n 阶牛顿(前向)插值多项式为:

N n ( x ) = f ( x 0 ) + f [ x 0 , x 1 ] ω 1 ( x ) + f [ x 0 , x 1 , x 2 ] ω 2 ( x ) + ⋯   + f [ x 0 , x 1 , ⋯   , x n ] ω n ( x ) ⇓ \qquad\qquad\begin{aligned}N_n(x)&=f(x_0)+f[x_0,x_1]\omega_1(x)+f[x_0,x_1,x_2]\omega_2(x)+\cdots\ \\&\quad+f[x_0,x_1,\cdots,x_n]\omega_n(x)\\ \newline\\ \newline&\qquad\qquad\qquad\qquad\qquad\qquad\Downarrow \\ \newline\end{aligned} Nn(x)=f(x0)+f[x0,x1]ω1(x)+f[x0,x1,x2]ω2(x)+ +f[x0,x1,,xn]ωn(x)
N n ( x 0 + t h ) = f ( x 0 ) + Δ f 0 h t h + Δ 2 f 0 2 h 2 t ( t − 1 ) h 2 + ⋯ + Δ n f 0 n ! h n t ( t − 1 ) ⋯ ( t − n + 1 ) h n \qquad\qquad\begin{aligned}N_n(x_0+th)&=f(x_0)+\dfrac{\Delta f_0}{h}th+\dfrac{\Delta^2 f_0}{2h^2}t(t-1)h^2+\cdots +\dfrac{\Delta^n f_0}{n!h^n}t(t-1)\cdots(t-n+1)h^n\end{aligned} Nn(x0+th)=f(x0)+hΔf0th+2h2Δ2f0t(t1)h2++n!hnΔnf0t(t1)(tn+1)hn
  = f 0 + t Δ f 0 + t ( t − 1 ) 2 Δ 2 f 0 + ⋯ + t ( t − 1 ) ⋯ ( t − n + 1 ) n ! Δ n f 0 \qquad\qquad\begin{aligned}\qquad\qquad\quad\ &=f_0+t\Delta f_0+\dfrac{t(t-1)}{2}\Delta^2 f_0+\cdots+\dfrac{t(t-1)\cdots(t-n+1)}{n!}\Delta^n f_0\end{aligned}  =f0+tΔf0+2t(t1)Δ2f0++n!t(t1)(tn+1)Δnf0

写成该表达式的目的,是为了更方便地使用“差分表”来进行实现。

\qquad

(4) 后向插值

\qquad 后向插值,正好与前向插值相反,是从区间 [ x 0 , x n − 1 ] [x_0,x_{n-1}] [x0,xn1] 的终点 x n − 1 x_{n-1} xn1 开始进行插值,任意待插值点的形式可写为 x = x n − 1 + t h ,   t ≤ 0 x=x_{n-1}+th,\ t\le0 x=xn1+th, t0。为了能够利用前向插值公式,可将插值节点按照 x n − 1 , x n − 2 , ⋯   , x 1 , x 0 x_{n-1},x_{n-2},\cdots,x_1,x_0 xn1,xn2,,x1,x0 的顺序进行倒序排列。

\qquad 倒序排列后, n n n 阶牛顿插值多项式为:

N n ( x ) = f ( x n − 1 ) + f [ x n − 1 , x n − 2 ] ( x − x n − 1 ) + f [ x n − 1 , x n − 2 , x n − 3 ] ( x − x n − 1 ) ( x − x n − 2 ) + ⋯   + f [ x 0 , x 1 , ⋯   , x n ] ( x − x n − 1 ) ( x − x n − 2 ) ⋯ ( x − x 0 ) \qquad\qquad\begin{aligned}N_n(x)&=f(x_{n-1})+f[x_{n-1},x_{n-2}](x-x_{n-1})\\ &+f[x_{n-1},x_{n-2},x_{n-3}](x-x_{n-1})(x-x_{n-2})+\cdots\ \\ &+f[x_0,x_1,\cdots,x_n](x-x_{n-1})(x-x_{n-2})\cdots(x-x_0)\end{aligned} Nn(x)=f(xn1)+f[xn1,xn2](xxn1)+f[xn1,xn2,xn3](xxn1)(xxn2)+ +f[x0,x1,,xn](xxn1)(xxn2)(xx0)

\qquad 同样地,可以记 n n n 阶多项式 ω n ( x ) \omega_n(x) ωn(x) 为:

ω n ( x ) = ( x − x n − 1 ) ( x − x n − 2 ) ⋯ ( x − x 0 ) = t ( t + 1 ) ⋯ ( t + n − 1 ) h n \qquad\qquad\omega_n(x)=(x-x_{n-1})(x-x_{n-2})\cdots(x-x_0)=t(t+1)\cdots(t+n-1)h^n ωn(x)=(xxn1)(xxn2)(xx0)=t(t+1)(t+n1)hn

\qquad 以及 m \textbf{m} m阶差分 f [ x k , x k − 1 , ⋯   , x k − m ] = ∇ m f k m ! h m f[x_k,x_{k-1},\cdots,x_{k-m}]=\dfrac{\nabla^m f_k}{m!h^m} f[xk,xk1,,xkm]=m!hmmfk

\qquad
\qquad 因此,等距插值节点时的 n n n 阶牛顿(后向)插值多项式为:

N n ( x ) = f ( x n − 1 ) + f [ x n − 1 , x n − 2 ] ω 1 ( x ) + f [ x n − 1 , x n − 2 , x n − 3 ] ω 2 ( x ) + ⋯   + f [ x n − 1 , x n − 2 , ⋯   , x 0 ] ω n ( x ) ⇓ \qquad\qquad\begin{aligned}N_n(x)&=f(x_{n-1})+f[x_{n-1},x_{n-2}]\omega_1(x)+f[x_{n-1},x_{n-2},x_{n-3}]\omega_2(x)+\cdots\ \\&\quad+f[x_{n-1},x_{n-2},\cdots,x_0]\omega_n(x)\\ \newline\\ \newline&\qquad\qquad\qquad\qquad\qquad\qquad\Downarrow \\ \newline\end{aligned} Nn(x)=f(xn1)+f[xn1,xn2]ω1(x)+f[xn1,xn2,xn3]ω2(x)+ +f[xn1,xn2,,x0]ωn(x)
N n ( x 0 + t h ) = f ( x n − 1 ) + ∇ f n − 1 h t h + ∇ 2 f n − 1 2 h 2 t ( t − 1 ) h 2 + ⋯ + ∇ n f n − 1 n ! h n t ( t − 1 ) ⋯ ( t − n + 1 ) h n \qquad\qquad\begin{aligned}N_n(x_0+th)&=f(x_{n-1})+\dfrac{\nabla f_{n-1}}{h}th+\dfrac{\nabla^2 f_{n-1}}{2h^2}t(t-1)h^2+\cdots +\dfrac{\nabla^n f_{n-1}}{n!h^n}t(t-1)\cdots(t-n+1)h^n\end{aligned} Nn(x0+th)=f(xn1)+hfn1th+2h22fn1t(t1)h2++n!hnnfn1t(t1)(tn+1)hn
  = f n − 1 + t ∇ f n − 1 + t ( t + 1 ) 2 ∇ 2 f n − 1 + ⋯ + t ( t + 1 ) ⋯ ( t + n − 1 ) n ! ∇ n f n − 1 \qquad\qquad\begin{aligned}\qquad\qquad\quad\ &=f_{n-1}+t\nabla f_{n-1}+\dfrac{t(t+1)}{2}\nabla^2 f_{n-1}+\cdots+\dfrac{t(t+1)\cdots(t+n-1)}{n!}\nabla^n f_{n-1}\end{aligned}  =fn1+tfn1+2t(t+1)2fn1++n!t(t+1)(t+n1)nfn1

写成该表达式的目的,是为了更方便地使用“差分表”来进行实现。

\qquad

实现代码

import numpy as np
import matplotlib.pyplot as plt

# 牛顿法:等距节点插值(前插公式)
def intNewtonforw_e(x,xcp,f,h,num):     
    diff_forw, diff_back = getdiff(xcp,f)
    hatf = np.zeros(len(x))
    for i in range(len(x)):
        if i%num == 0:
            hatf[i] = f(x[i])
            continue
        t = i/num
        hatf[i] = hatf[0]
        tmp = 1
        prodn = 1
        for n in range(1,len(xcp)-1):#插值多项式阶数为n=len(xcp)-1阶,可以小于n
            tmp = tmp*(t-n+1)
            prodn = prodn * n
            hatf[i] += tmp * diff_forw[n]/prodn                   
    return hatf

# 牛顿法:等距节点插值(后插公式)
def intNewtonback_e(x,xcp,f,h,num):     
    diff_forw, diff_back = getdiff(xcp,f)
    xn = len(x)-1
    hatf = np.zeros(len(x))
    for i in range(len(x)):
        if i%num == 0:
            hatf[xn-i] = f(x[xn-i])
            continue
        t = - i/num
        hatf[xn-i] = hatf[xn]
        tmp = 1
        prodn = 1
        for n in range(1,len(xcp)-1):#插值多项式阶数为nlen(xcp)-1阶,可以小于n
            tmp = tmp*(t+n-1)
            prodn = prodn * n
            hatf[xn-i] += tmp * diff_back[n]/prodn                     
    return hatf
    
# 获取各阶前向差分和后向差分    
def getdiff(xcp,f):
    # np.set_printoptions(precision=5)
    diff_forw = np.zeros(len(xcp))
    diff_back = np.zeros(len(xcp))
    t0 = f(xcp)
    diff_forw[0] = t0[0]
    diff_back[0] = t0[-1]    
    for n in range(1,len(xcp)):
        fn0 = t0        
        fn1 = np.concatenate((np.ones(1),fn0[0:-1]))    
        t1 = fn0 - fn1
        diff_forw[n] = t1[1]
        diff_back[n] = t1[-1]
        t0 = t1[1:]
    return diff_forw, diff_back        

if __name__ == '__main__':    
    plt.figure(figsize=(7, 4))    
    # parameters
    xs = -13
    xe = 13
    h = 1                           # 相邻等距节点的间隔
    num = 10                        # 两个等距节点之间再等距划分10个点
    t = h/num                       # 相邻节点之间的待插值点间隔
    x = np.arange(xs,xe+t,t)        # 等距节点之间再等分后的待插值点
    xcp = np.arange(xs,xe+h,h)      # 等距节点
    # function to be interpolated
    f = lambda x: x**2 + 30*np.sin(x)     
    plt.plot(x,f(x))        
    ##Newton Interpolation  
    hatf = intNewtonforw_e(x,xcp,f,h,num) #前向插值
    plt.plot(x,hatf) 
    hatf = intNewtonback_e(x,xcp,f,h,num) #后向插值   
    plt.plot(x,hatf)        
    # plot control point
    for i in range(len(xcp)):    
        plt.plot(xcp[i],f(xcp[i]),'ro',markerfacecolor='none')        
    plt.legend(['original','Newton forward','Newton backward','control point'])
    plt.title('Newton Interpolation')
    plt.show()

运行结果:

( 1 ) (1) (1) 前插公式
\qquad 在这里插入图片描述

( 2 ) (2) (2) 后插公式
\qquad 在这里插入图片描述

( 3 ) (3) (3) 将前插公式和后插公式的结果显示在同一张图
\qquad 在这里插入图片描述
\qquad
参考
基于径向基函数(RBF)的函数插值
\qquad
\qquad
\qquad
\qquad

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值