实验原理
-
熟悉并掌握Lagrange插值的构造原理;会计算在给定点的函数值
Lagrange插值是一种基于Lagrange基函数的插值方法。给定一组数据节点(x,y),其中x是自变量,y是因变量,其插值的目标是构造一个多项式函数,通过这个多项式函数来拟合已知的数据节点,并用于对其他未知点进行插值预测。具体构造原理如下:
-
对于给定的数据节点 ( x k , y k ) (x_k, y_k) (xk,yk),构造基函数 l k ( x ) l_k(x) lk(x),其中 i i i表示数据节点的索引。基函数 l k ( x ) l_k(x) lk(x)的计算方式为:
l k ( x ) = ∏ j = 0 , j ≠ k n x − x j x k − x j l_k(x) = \prod_{j=0, j\neq k}^n \frac{x - x_j}{x_k - x_j} lk(x)=j=0,j=k∏nxk−xjx−xj
这里, n n n表示数据节点的总数, x j x_j xj表示第 j j j个数据节点的 x x x值。
-
使用基函数 l k ( x ) l_k(x) lk(x)来构造Lagrange插值多项式 L ( x ) L(x) L(x)。 L ( x ) L(x) L(x)的计算方式为:
L ( x ) = ∑ k = 0 n y k ⋅ l k ( x ) L(x) = \sum_{k=0}^n y_k \cdot l_k(x) L(x)=k=0∑nyk⋅lk(x)
这里, y k y_k yk表示第 k k k个数据节点的 y y y值。
-
最终得到的Lagrange插值多项式 L ( x ) L(x) L(x)就是通过已知数据节点进行插值预测的函数。可以使用该函数计算其他未知点的预测值。
-
-
熟悉并掌握Newton插值的构造原理;会计算在给定点的函数值。
Newton插值是一种基于差商的插值方法,它使用差商的概念来构造插值多项式。具体来说,Newton插值法首先选择一组数据节点,然后,通过差商的计算来逐步构造插值多项式。对于给定的数据节点,可以通过以下递归公式计算差商:
f [ x i ] = f ( x i ) f[x_i] = f(x_i) f[xi]=f(xi)
f [ x i , x i + 1 , . . . , x i + k ] = f [ x i + 1 , x i + 2 , . . . , x i + k ] − f [ x i , x i + 1 , . . . , x i + k − 1 ] x i + k − x i f[x_i, x_{i+1}, ..., x_{i+k}] = \frac{f[x_{i+1}, x_{i+2}, ..., x_{i+k}] - f[x_i, x_{i+1}, ..., x_{i+k-1}]}{x_{i+k} - x_i} f[xi,xi+1,...,xi+k]=xi+k−xif[xi+1,xi+2,...,xi+k]−f[xi,xi+1,...,xi+k−1]
其中, f [ x i , x i + 1 , . . . , x i + k ] f[x_i, x_{i+1}, ..., x_{i+k}] f[xi,xi+1,...,xi+k]表示在节点 x i , x i + 1 , . . . , x i + k x_i, x_{i+1}, ..., x_{i+k} xi,xi+1,...,xi+k处的k阶差商, f [ x i ] f[x_i] f[xi]表示在数据节点 x i x_i xi处的函数值。
通过递归计算差商,可以得到一个多项式的系数表,用于构造Newton插值多项式。最终,多项式的形式为:
P ( 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 ) + . . . P(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) + ... P(x)=f[x0]+f[x0,x1](x−x0)+f[x0,x1,x2](x−x0)(x−x1)+...
在给定的数据节点上,该多项式与原函数完全一致。最后,将待插值点的横坐标代入插值多项式中,即可得到相应的插值结果。
-
比较Lagrange插值与Newton插值的优缺点
Lagrange插值在数据点附近具有高精度,适用于需要高精度插值的情况。Newton插值在节点附近具有高精度,同时具有较好的承继性,适用于需要稳定性和高精度插值的情况。在实际应用中,可以根据具体需求和限制选择合适的插值方法。
代码实现
分别用Lagrange和Newton插值计算深度为600、1000、1200处的水温
Lagrange插值
def lagrange_interpolation(x, y, value):
# 判断输入的数据节点x和y是否数量一致
if len(x) != len(y):
print("数据节点数量不一致!")
return None
n = len(x) # 数据节点的个数
result = 0.0 # 待插值点处的水温
for k in range(n):
l_k = 1.0 # 基函数l_k(x)的初始值
for i in range(n):
if i != k:
l_k *= (value - x[i]) / (x[k] - x[i])
result += y[k] * l_k
return result
# 测试数据
depth = [466, 741, 950, 1422, 1634] # 深度数据节点
temperature = [7.04, 4.28, 3.40, 2.54, 2.13] # 温度数据节点
# 待插值点的深度
depth_values = [600, 1000, 1200]
# 计算并输出水温
for value in depth_values:
interpolated_temperature = lagrange_interpolation(depth, temperature, value)
print(f"深度为{value}处的水温为:{interpolated_temperature}℃")
打印输出:
深度为600处的水温为:5.386310672253148℃
深度为1000处的水温为:3.2716309909438093℃
深度为1200处的水温为:2.900097926989794℃
Newton插值
import numpy as np
# 已知数据节点
depth = np.array([466, 741, 950, 1422, 1634])
temperature = np.array([7.04, 4.28, 3.40, 2.54, 2.13])
# 计算差商
def divided_differences(x, y):
n = len(x)
coefficients = np.zeros((n, n))
coefficients[:, 0] = y
for j in range(1, n):
for i in range(n-j):
coefficients[i, j] = (coefficients[i+1, j-1] - coefficients[i, j-1]) / (x[i+j] - x[i])
return coefficients
# 计算插值多项式的系数表
coefficients = divided_differences(depth, temperature)
# 计算插值结果
def newton_interpolation(x, coefficients, data_points):
n = len(data_points)
result = 0
for i in range(n):
term = coefficients[0, i]
for j in range(i):
term *= (x - data_points[j])
result += term
return result
# 计算深度为600、1000和1200处的水温
depths_to_interpolate = np.array([600, 1000, 1200])
temperatures_interpolated = newton_interpolation(depths_to_interpolate, coefficients, depth)
print("插值结果:")
for i in range(len(depths_to_interpolate)):
print("深度{}m的水温为{:}℃".format(depths_to_interpolate[i], temperatures_interpolated[i]))
打印输出:
深度为600处的水温为:5.386310672253148℃
深度为1000处的水温为:3.2716309909438093℃
深度为1200处的水温为:2.900097926989794℃
从实验结果来看,Lagrange插值和Newton插值在计算深度为600、1000和1200处的水温时,结果都非常接近真实的温度数据。这说明Lagrange插值和Newton插值方法在这组数据上具有一定的准确性和可靠性。
分别求相应的四次Lagrange和Newton插值多项式,画出插值函数与原函数的图形并做比较
Lagrange插值
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
def lagrange_interpolation(x, y, value):
if len(x) != len(y):
print("数据节点数量不一致!")
return None
n = len(x)
result = 0.0
for k in range(n):
l_k = 1.0
for i in range(n):
if i != k:
l_k *= (value - x[i]) / (x[k] - x[i])
result += y[k] * l_k
return result
# 设置中文字体
font = FontProperties(fname=r"C:\Windows\Fonts\simsun.ttc", size=12)
# 数据节点
x = [0.4, 0.5, 0.6, 0.7, 0.8]
y = [0.6325, 0.7071, 0.7746, 0.8367, 0.8944]
# 生成插值函数的横坐标
x_interp = np.linspace(x[0], x[-1], 100)
# 计算插值函数的纵坐标
y_interp = [lagrange_interpolation(x, y, value) for value in x_interp]
# 绘制原函数和插值函数的图形
plt.plot(x_interp, y_interp, label='插值函数')
plt.scatter(x, y, color='red', label='原始数据')
plt.xlabel('x', fontproperties=font)
plt.ylabel('y', fontproperties=font)
plt.title('Lagrange插值', fontproperties=font)
plt.legend(prop=font)
plt.show()
Newton插值
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
# 给定数据
x = np.array([0.4, 0.5, 0.6, 0.7, 0.8])
y = np.array([0.6325, 0.7071, 0.7746, 0.8367, 0.8944])
# 计算差商
def divided_differences(x, y):
n = len(x)
coefficients = np.zeros((n, n))
coefficients[:, 0] = y
for j in range(1, n):
for i in range(n-j):
coefficients[i, j] = (coefficients[i+1, j-1] - coefficients[i, j-1]) / (x[i+j] - x[i])
return coefficients
# 计算插值多项式的系数
coefficients = divided_differences(x, y)
# 计算插值结果
def newton_interpolation(x, coefficients, data_points):
n = len(data_points)
result = 0
for i in range(n):
term = coefficients[i]
for j in range(i):
term *= (x - data_points[j])
result += term
return result
# 计算插值函数在指定x值处的值
x_interp = np.linspace(x[0], x[-1], 100)
y_interp = [newton_interpolation(x, coefficients[0], [0.4, 0.5, 0.6, 0.7, 0.8]) for x in x_interp]
# 设置中文字体
font = FontProperties(fname=r"C:\Windows\Fonts\simsun.ttc", size=12)
# 绘制原函数和插值函数的图形
plt.plot(x_interp, y_interp, label='插值函数')
plt.scatter(x, y, color='red', label='原始数据')
plt.xlabel('x', fontproperties=font)
plt.ylabel('y', fontproperties=font)
plt.title('Newton插值', fontproperties=font)
plt.legend(prop=font)
plt.show()
由实验结果可以看出,Lagrange插值多项式和Newton插值多项式在给定的数据节点上都能很好地拟合原始数据。从图形上看,插值函数与原始数据点非常接近,表明插值方法能够较好地反映原始数据的趋势。
课外练习
为了观察多项式插值问题的Runge现象,使用函数f(x) = 1 / (1 + x^2) 在区间[-5, 5] 上进行Lagrange插值,并比较5次和10次插值多项式的结果。实现代码如下:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
def lagrange_interpolation(x, y, value):
if len(x) != len(y):
print("数据节点数量不一致!")
return None
n = len(x)
result = 0.0
for k in range(n):
l_k = 1.0
for i in range(n):
if i != k:
l_k *= (value - x[i]) / (x[k] - x[i])
result += y[k] * l_k
return result
# 定义函数 f(x) = 1 / (1 + x^2)
def f(x):
return 1 / (1 + x**2)
# 生成等距节点
x = np.linspace(-5, 5, 100)
y = f(x)
# 生成5次插值多项式
x_interp_5 = np.linspace(-5, 5, 5)
y_interp_5 = f(x_interp_5)
interp_5 = lagrange_interpolation(x_interp_5, y_interp_5, x)
# 生成10次插值多项式
x_interp_10 = np.linspace(-5, 5, 10)
y_interp_10 = f(x_interp_10)
interp_10 = lagrange_interpolation(x_interp_10, y_interp_10, x)
# 设置中文字体
font = FontProperties(fname=r"C:\Windows\Fonts\simsun.ttc", size=12)
# 绘制原始函数和插值结果
plt.plot(x, y, label='原始函数')
plt.plot(x, interp_5, label='5次插值')
plt.plot(x, interp_10, label='10次插值')
plt.xlabel('x',fontproperties=font)
plt.ylabel('y',fontproperties=font)
plt.title('Lagrange插值结果',fontproperties=font)
plt.legend(prop=font)
plt.show()
由实验结果可以看出,在区间[-5, 5]上,随着插值多项式的阶数增加,插值结果在区间两端出现了明显的振荡现象,这就是Runge现象。这个现象表明,在某些情况下,使用更高阶的插值多项式并不一定能够得到更好的结果,反而可能导致不稳定的插值效果。