首先给出,n次插值基函数定义
若 n 次 多 项 式 l j ( x ) ( j = 1 , 2 , … , n ) 在 n + 1 个 节 点 x 0 < x 1 < … < x n 上 满 足 条 件 若n次多项式l_j(x)(j=1,2,\ldots,n)在n+1个节点x_0
l j ( x k ) = { 1 , k = j , j , k = 0 , 1 , … , n , 0 , k ≠ j , l_j(x_k)=\begin{cases} 1,k=j,\\ \qquad\qquad j,k=0,1,\ldots,n,\\ 0,k\neq j, \end{cases} lj(xk)=⎩⎪⎨⎪⎧1,k=j,j,k=0,1,…,n,0,k=j,
就称这 n + 1 个 n 次 多 项 式 l 0 ( x ) , l 1 ( x ) , … , l n ( x ) 为 节 点 x 0 , x 1 , … , x n 上 的 n次插值基函数 . n+1个n次多项式l_0(x),l_1(x),\ldots,l_n(x)为节点x_0,x_1,\ldots,x_n上的\textbf{n次插值基函数}. n+1个n次多项式l0(x),l1(x),…,ln(x)为节点x0,x1,…,xn上的n次插值基函数.
由此可以得到 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 ) , k = 0 , 1 , … , n . l_k(x)=\frac{(x-x_0)\ldots(x-x_{k-1})(x-x_{k+1})\ldots(x-x_n)}{(x_k-x_0)\ldots(x_k-x_{k-1})(x_k-x_{k+1})\ldots(x_k-x_n)},k=0,1,\ldots,n. lk(x)=(xk−x0)…(xk−xk−1)(xk−xk+1)…(xk−xn)(x−x0)…(x−xk−1)(x−xk+1)…(x−xn),k=0,1,…,n.
显然它满足n次插值基函数定义的条件.于是,满足 L n ( x j ) = y j , j = 0 , 1 , … , n . L_n(x_j)=y_j,j=0,1,\ldots,n. Ln(xj)=yj,j=0,1,…,n.条件的 L n ( x ) L_n(x) Ln(x)可表示为
L n ( x ) = ∑ k = 0 n y k l k ( x ) . L_n(x)=\sum_{k = 0}^{n}y_kl_k(x). Ln(x)=k=0∑nyklk(x).
形如上式的插值多项式 L n ( x ) 称 为 拉格朗日(Lagrange)插值多项式 L_n(x)称为\textbf{拉格朗日(Lagrange)插值多项式} Ln(x)称为拉格朗日(Lagrange)插值多项式
由 l k ( x ) l_k(x) lk(x)的定义,知
L n ( x j ) = ∑ k = 0 n y k l k ( x j ) = y j , j = 0 , 1 , … , n . L_n(x_j)=\sum_{k = 0}^{n}y_kl_k(x_j)=y_j,\quad j=0,1,\ldots,n. Ln(xj)=k=0∑nyklk(xj)=yj,j=0,1,…,n.
import numpy as np
from sympy import expand
from sympy.abc import x
# 自己原创
# 拉格朗日插值多项式输出显示形式与scipy.interpolate模块的同名函数有差距,有待继续优化
def lagrange(x_list: list, y_array: np.ndarray):
"""
实现拉格朗日插值函数
:param x_list: 插值点横坐标列表
:param y_array: 插值点纵坐标数组
:return: 拉格朗日插值多项式
"""
degree = y_array.shape[0]
l_n = 0
for k in range(degree):
# 注意不能同时对列表进行遍历和删除,否则索引会超出范围报错,有几种方式解决,此处使用切片
l_n += y_array[k] * lagrange_base_function(k, x_list[::])
return expand(l_n)
# 自己原创
def lagrange_base_function(k, x_list: list):
"""
实现拉格朗日插值基函数
:param k: 插值结点横坐标x_k的下标
:param x_list: 插值点横坐标列表
:return: 第k个插值结点的插值基函数
"""
x_k = x_list[k] # 取得xk处的值
x_list.pop(k) # 删除xk处的值
x_list = np.array(x_list)
# 向量运算实现插值基函数
return np.prod((x - x_list) / (x_k - x_list))
# 按元素实现插值基函数
# l_k = 1
# for i in range(x_coefficient.shape[0]):
# l_k *= (x - x_coefficient[i]) / (x_k - x_coefficient[i])
# return l_k
if __name__ == '__main__':
# 拉格朗日插值多项式测试成功,来源详见李庆扬数值分析第5版P48,e.x.1
x_coefficient_list = [1, -1, 2]
x_coefficient_array = np.array(x_coefficient_list)
y = np.array([0, -3, 4])
lagrange_interpolation_polynomial = lagrange(x_coefficient_list, y)
print("拉格朗日插值多项式为:{}".format(lagrange_interpolation_polynomial))
# 计算拉格朗日插值多项式在x=2处的值
print("拉格朗日插值多项式在x=2处的值为:{}".format(lagrange_interpolation_polynomial.subs(x, 2)))