数值分析——牛顿插值

牛顿插值

为什么要有牛顿插值

拉格朗日插值简单方便,可以一下计算出基函数,但有其本身的缺陷,回忆下拉格朗日插值基函数的形式: l k ( x ) = ( x − x 0 ) ( x − x 1 ) . . . ( x − x k − 1 ) ( x − x k + 1 ) . . . ( x − x n ) ( x k − x 0 ) ( x k − x 1 ) . . . ( x k − x k − 1 ) ( x k − x k + 1 ) . . . ( x k − x n ) l_k(x)=\dfrac{(x-x_0)(x-x_1)...(x-x_{k-1})(x-x_{k+1})...(x-x_n)}{(x_k-x_0)(x_k-x_1)...(x_k-x_{k-1})(x_k-x_{k+1})...(x_k-x_n)} lk(x)=(xkx0)(xkx1)...(xkxk1)(xkxk+1)...(xkxn)(xx0)(xx1)...(xxk1)(xxk+1)...(xxn)

每一个插值基函数都与所有数据点有关,这意味着如果增加一个数据点,所有基函数要重新计算。

因此我们需要一个可以逐步生成插值多项式的基函数,它应当在插值时,满足:

p n + 1 ( x ) = p n ( x ) + u n + 1 ( x ) p_{n+1}(x)=p_n(x)+u_{n+1}(x) pn+1(x)=pn(x)+un+1(x),其中 p n + 1 ( x ) , p n ( x ) p_{n+1}(x),p_{n}(x) pn+1(x)pn(x)分别是 n + 1 n+1 n+1 n n n次插值多项式,这样增加一个节点时只需在当前插值多项式上加一个多余项就可以。牛顿插值就是这样一种方法。

牛顿插值基函数

现在来尝试构造一下插值基函数,虽然其形式课件里给了,但通过之前的要求未必不能自己来尝试一下找规律。

首先,如果只有一个数据点,那必然要求 p ( x 0 ) = f ( x 0 ) p(x_0)=f(x_0) p(x0)=f(x0),这可以视为系数为 f ( x 0 ) f(x_0) f(x0),基函数为 ω 0 ( x ) = 1 \omega_0(x)=1 ω0(x)=1

当增加一个数据点时,则有 p ( x 0 ) = f ( x 0 ) + a 1 ω 1 ( x 0 ) = f ( x 0 ) , p ( x 1 ) = f ( x 0 ) + a 1 ω 1 ( x 1 ) = f ( x 1 ) p(x_0)=f(x_0)+a_1\omega_1(x_0)=f(x_0),p(x_1)=f(x_0)+a_1\omega_1(x_1)=f(x_1) p(x0)=f(x0)+a1ω1(x0)=f(x0),p(x1)=f(x0)+a1ω1(x1)=f(x1),这样可以明确的是 ω 1 ( x ) \omega_1(x) ω1(x)一定含有 x − x 0 x-x_0 xx0项,系数 a 1 a_1 a1不能直接取 f ( x 1 ) f(x_1) f(x1),而是与 f ( x 1 ) − f ( x 0 ) f(x_1)-f(x_0) f(x1)f(x0)有关。如果把系数全部撇到 a 1 a_1 a1里先不管,那么基函数第二项为 ω 1 ( x ) = ( x − x 0 ) \omega_1(x)=(x-x_0) ω1(x)=(xx0),系数 a 1 = f ( x 1 ) − f ( x 0 ) x 1 − x 0 a_1=\dfrac{f(x_1)-f(x_0)}{x_1-x_0} a1=x1x0f(x1)f(x0)

在增加一个数据点时,同理可推出 ω 2 ( x ) = ( x − x 0 ) ( x − x 1 ) \omega_2(x)=(x-x_0)(x-x_1) ω2(x)=(xx0)(xx1)。且此时有: p ( x 2 ) = f ( x 0 ) + a 1 ω 1 ( x 2 ) + a 2 ω 2 ( x 2 ) = f ( x 2 ) p(x_2)=f(x_0)+a_1\omega_1(x_2)+a_2\omega_2(x_2)=f(x_2) p(x2)=f(x0)+a1ω1(x2)+a2ω2(x2)=f(x2)。可以解得: a 2 = f ( x 2 ) − f ( x 0 ) − a 1 ( x 2 − x 0 ) ( x 2 − x 0 ) ( x 2 − x 1 ) = f ( x 2 ) − f ( x 1 ) x 2 − x 1 − f ( x 1 ) − f ( x 0 ) x 1 − x 0 x 2 − x 0 a_2=\dfrac{f(x_2)-f(x_0)-a_1(x_2-x_0)}{(x_2-x_0)(x_2-x_1)}=\dfrac{\dfrac{f(x_2)-f(x_1)}{x_2-x_1}-\dfrac{f(x_1)-f(x_0)}{x_1-x_0}}{x_2-x_0} a2=(x2x0)(x2x1)f(x2)f(x0)a1(x2x0)=x2x0x2x1f(x2)f(x1)x1x0f(x1)f(x0)

可以发现系数有明显的规律。

如果定义一阶差商 f [ x 0 , x 1 ] = f ( x 1 ) − f ( x 0 ) x 1 − x 0 f[x_0,x_1]=\dfrac{f(x_1)-f(x_0)}{x_1-x_0} f[x0,x1]=x1x0f(x1)f(x0)

定义n阶差商 f [ x 0 , x 1 , . . . , x n ] = f [ x 1 , . . . , x n ] − f [ x 0 , . . . , x n − 1 ] x n − x 0 f[x_0,x_1,...,x_n]=\dfrac{f[x_1,...,x_n]-f[x_0,...,x_{n-1}]}{x_n-x_0} f[x0,x1,...,xn]=xnx0f[x1,...,xn]f[x0,...,xn1]

那么显然,每一项系数是: a k = f [ x 0 , x 1 , . . . , x k ] a_k=f[x_0,x_1,...,x_k] ak=f[x0,x1,...,xk]

每一项基函数是: ω k = ( x − x 0 ) ( x − x 1 ) . . . ( x − x k − 1 ) \omega_k=(x-x_0)(x-x_1)...(x-x_{k-1}) ωk=(xx0)(xx1)...(xxk1)

那么牛顿插值公式就是: p ( x ) = ∑ k = 0 n a k ω k ( x ) p(x)=\sum^n_{k=0}a_k\omega_k(x) p(x)=k=0nakωk(x)

等距牛顿插值

当推出牛顿插值函数通用的表达后,有一种常见情况值得单独讨论一下。

差商实际上并不好计算,但某些情况下(数据点自变量距离相等)可以用差分表示。

定义差分 Δ f i = f ( x i + h ) − f ( x i ) , . . . , Δ n f i = Δ ( Δ n − 1 f i ) = Δ n − 1 f i + 1 − Δ n − 1 f i \Delta f_i=f(x_i+h)-f(x_i),...,\Delta^n f_i=\Delta(\Delta^{n-1}f_i)=\Delta^{n-1}f_{i+1}-\Delta^{n-1}f_i Δfi=f(xi+h)f(xi),...,Δnfi=Δ(Δn1fi)=Δn1fi+1Δn1fi

那么如果 x 0 , x 1 , . . . , x n x_0,x_1,...,x_n x0,x1,...,xn等距,假设这个距离是 h h h,差分与差商就有一个简单对应关系:

f [ x 0 , x 1 ] = f ( x 1 ) − f ( x 0 ) x 1 − x 0 = Δ f 0 h f[x_0,x_1]=\dfrac{f(x_1)-f(x_0)}{x_1-x_0}=\dfrac{\Delta f_0}{h} f[x0,x1]=x1x0f(x1)f(x0)=hΔf0

f [ x 0 , x 1 , x 2 ] = f [ x 1 , x 2 ] − f [ x 0 , x 1 ] x 2 − x 0 = Δ 2 f 0 2 h 2 f[x_0,x_1,x_2]=\dfrac{f[x_1,x_2]-f[x_0,x_1]}{x_2-x_0}=\dfrac{\Delta^2f_0}{2h^2} f[x0,x1,x2]=x2x0f[x1,x2]f[x0,x1]=2h2Δ2f0

易推出:

f [ x 0 , x 1 , . . . , x n ] = Δ m f 0 m ! h m f[x_0,x_1,...,x_n]=\dfrac{\Delta^mf_0}{m!h^m} f[x0,x1,...,xn]=m!hmΔmf0

代码示例

对函数 f = c o s x f=cosx f=cosx进行等距插值,从 0 0 0开始,数据点间距 0.1 0.1 0.1

import numpy as np
import matplotlib.pyplot as plt

# 定义数据点间距
h = 0.1
# 定义插值次数
n = 4

# 取数据点
xdata = np.linspace(0, h * (n - 1), n)
ydata = np.cos(xdata)

# 计算各阶差分
def data_different(xdata, ydata):
    num = len(xdata)
    h = xdata[1] - xdata[0]
    dif = np.zeros((num, 1))
    dif_table = ydata
    for i in range(num):
        dif[i] = dif_table[0] / (np.math.factorial(i) * h ** i)
        dif_table = np.diff(dif_table)
    return dif

# 计算插值函数
def px(factor, x, xdata, ydata):
    w = np.zeros((len(x), len(factor)))
    wk = np.ones(len(x))
    for i in range(len(factor)):
        w[:,i] = wk
        wk = wk*(x-xdata[i])
    return w@factor

plot_x = np.linspace(-2, 2, 40*n)
plot_y = px(data_different(xdata,ydata), plot_x, xdata, ydata)
p1, = plt.plot(plot_x, plot_y)
p2, = plt.plot(plot_x, np.cos(plot_x))
p3 = plt.scatter(xdata, ydata)
p3 = plt.scatter(xdata, ydata)
plt.legend([p1, p2], ["p(x)", "f(x)"])
plt.show()

当数据点数为 4 4 4时,插值多项式的图像如下:

在这里插入图片描述
当数据点数目为 8 8 8时,插值多项式图像如下:
在这里插入图片描述
现在,取 n = 16 n=16 n=16,并画出更大范围图像时,得到结果如下:
在这里插入图片描述
可以看出,插值并不能预知数据点范围外部的图像变化,插值插值,一般只用来计算数据点之间的函数值。

牛顿插值和拉格朗日插值比较

事实上,牛顿插值函数和拉格朗日插值函数完全一样,之前已经证明过这个定理,多项式插值函数唯一。
两者的区别仅仅是不同情形的计算方式上的优劣。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值