Hermite Interpolation
Hermite插值多项式
Hermite插值是一种插值方法,可以通过给定的点和导数值构造插值多项式。给定点\((x_0,y_0),(x_1,y_1),...,(x_n,y_n)\)和导数值\(y'_0,y'_1,...,y'_n\),可以构造插值多项式。本文介绍如何使用Newton差商生成Hermite插值多项式。
Newton差商
Newton差商公式是一个递归定义的公式,可以写成一个表格的形式:
\[ f[x_i,x_{i+1},...,x_{i+j}]=\frac{f[x_{i+1},x_{i+2},...,x_{i+j}]-f[x_i,x_{i+1},...,x_{i+j-1}]}{x_{i+j}-x_i}\tag{1} \]
给定一组点\((x_0,y_0),(x_1,y_1),...,(x_n,y_n)\),可以通过差商表格计算出插值多项式的系数。第一列和第二列分别是\(x_i\)和\(y_i\),后面的列是差商,通过递归公式一列一列地计算出来。下面是一个生成差商表格的Python函数:
1 | import numpy as np |
比如给定点\((0,0),(1,16),(2,46),(3,94),(4,160)\),可以生成差商表格:
1 | x = [0, 1, 2, 3, 4] |
输出结果:
\(x\) | \(y\) | \(f[x_0,x_1]\) | \(f[x_0,x_1,x_2]\) | \(f[x_0,x_1,x_2,x_3]\) | \(f[x_0,x_1,x_2,x_3,x_4]\) |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 |
1 | 16 | 16 | 0 | 0 | 0 |
2 | 46 | 30 | 7 | 0 | 0 |
3 | 94 | 48 | 9 | 0.666667 | 0 |
4 | 160 | 66 | 9 | 0 | -0.166667 |
Newton插值
用Newton差商可以得到插值多项式的系数,然后可以用这些系数构造插值多项式。插值多项式的形式是:
\[ p(x)=f[x_0]+\sum_{i=1}^{n}f[x_0,x_1,...,x_i]\prod_{j=0}^{i-1}(x-x_j)\tag{2} \]
用上一节生成的差商表格,可以写出
\[ p(x)=(x-0)+16(x-0)(x-1)+7(x-0)(x-1)(x-2)+\frac{2}{3}(x-0)(x-1)(x-2)(x-3)\tag{3} \] 可以看出,插值多项式的系数是差商表格的对角线元素。
1 | def newton_interpolation(tb): |
绘制插值多项式:
1 | def plot_interpolation(p, x, y): |
Hermite插值
在Newton差商表格的基础上,重复每个点两次,并且设置其导数值作为一阶差商。然后使用原来的计算方法生成差商表格,跳过已经计算过的差商(已知的导数),使用和Newton插值多项式一样的方法就可以得到Hermite插值多项式。
下面是一个用于生成Hermite插值多项式的生成Newton差商表格的Python函数:
1 | def generate_hermite_diff_quotient_table(x, y, y_prime): |
比如给定点\((0,0),(1,16),(2,46),(3,94),(4,160)\)和导数值\(0.5,0.8,1.2,1.8\),可以生成差商表格:
1 | x = [0, 1, 2, 3, 4] |
\(x\) | \(y\) | \(f[x_0,x_0]\) | \(f[x_0,x_0,x_1]\) | \(f[x_0,x_0,x_1,x_1]\) | \(f[x_0,x_0,x_1,x_1,x_2]\) | \(f[x_0,x_0,x_1,x_1,x_2,x_2]\) | \(f[x_0,x_0,x_1,x_1,x_2,x_2,x_3]\) | \(f[x_0,x_0,x_1,x_1,x_2,x_2,x_3,x_3]\) | \(f[x_0,x_0,x_1,x_1,x_2,x_2,x_3,x_3,x_4]\) | \(f[x_0,x_0,x_1,x_1,x_2,x_2,x_3,x_3,x_4,x_4]\) |
---|---|---|---|---|---|---|---|---|---|---|
0.0 | 0.0 | / | / | / | / | / | / | / | / | / |
0.0 | 0.0 | 0.5 | / | / | / | / | / | / | / | / |
1.0 | 16.0 | 16.0 | 15.5 | / | / | / | / | / | / | / |
1.0 | 16.0 | 0.5 | -15.5 | -31.0 | / | / | / | / | / | / |
2.0 | 46.0 | 30.0 | 29.5 | 22.5 | 26.75 | / | / | / | / | / |
2.0 | 46.0 | 0.8 | -29.2 | -58.7 | -40.60 | -33.675000 | / | / | / | / |
3.0 | 94.0 | 48.0 | 47.2 | 38.2 | 48.45 | 29.683333 | 21.119444 | / | / | / |
3.0 | 94.0 | 1.2 | -46.8 | -94.0 | -66.10 | -57.275000 | -28.986111 | -16.701852 | / | / |
4.0 | 160.0 | 66.0 | 64.8 | 55.8 | 74.90 | 47.000000 | 34.758333 | 15.936111 | 8.159491 | / |
4.0 | 160.0 | 1.8 | -64.2 | -129.0 | -92.40 | -83.650000 | -43.550000 | -26.102778 | -10.509722 | -4.667303 |
然后可以用和Newton插值多项式一样的方法生成Hermite插值多项式:
\[ p(x)=0+0.5(x-0)+15.5(x-0)(x-0)+-31(x-0)(x-0)(x-1)+26.75(x-0)(x-0)(x-1)(x-1)+-33.675(x-0)(x-0)(x-1)(x-1)(x-2)+21.119444(x-0)(x-0)(x-1)(x-1)(x-2)(x-2)+-16.701852(x-0)(x-0)(x-1)(x-1)(x-2)(x-2)(x-3)+8.159491(x-0)(x-0)(x-1)(x-1)(x-2)(x-2)(x-3)(x-3)-4.667303(x-0)(x-0)(x-1)(x-1)(x-2)(x-2)(x-3)(x-3)(x-4) \]
1 | p = newton_interpolation(hermite_diff_quotient_table) |
测试该插值多项式在给定点的导数值:
1 | def test_interpolation(p, x, y, y_prime=None): |
返回True,说明插值多项式在给定点的导数值是正确的。
Hermite Interpolation
https://grahamzen.github.io/2024/10/30/hermite-interpolation/