164 lines
5.3 KiB
Python
164 lines
5.3 KiB
Python
import math
|
||
|
||
# 定义插值点
|
||
list_x = [10, 11, 12, 13] # 自变量列表
|
||
list_y = [2.3026, 2.3979, 2.4849, 2.5649] # 因变量列表
|
||
|
||
# 定义原函数和其导函数计算结果
|
||
def FxDiff_n(x, n):
|
||
"""
|
||
计算自然对数函数 ln(x) 的 n 阶导数值。
|
||
|
||
参数:
|
||
x (float): 自变量值,要求 x > 0。
|
||
n (int): 导数的阶数,n >= 0。
|
||
|
||
返回:
|
||
float: ln(x) 的 n 阶导数值。
|
||
"""
|
||
result = 0
|
||
if n == 0:
|
||
result = math.log(x) # 原函数 ln(x)
|
||
else:
|
||
result = (-1)**(n+1) * math.factorial(n-1) / (x**n) # n 阶导数公式
|
||
|
||
return result
|
||
|
||
# 获取与待求 x 最接近的两个点
|
||
def GetClosestTwo(x, list_x):
|
||
"""
|
||
获取与待求点 x 最接近的两个插值点的索引。
|
||
|
||
参数:
|
||
x (float): 待插值的自变量值。
|
||
list_x (list of float): 自变量列表,要求已按升序排列。
|
||
|
||
返回:
|
||
tuple of int: 最接近的两个点的索引 (i, j),满足 list_x[i] <= x < list_x[j]。
|
||
"""
|
||
for i in range(0, len(list_x)):
|
||
if x < list_x[i]:
|
||
return i-1, i
|
||
return len(list_x)-2, len(list_x)-1
|
||
|
||
# 获取与待求 x 最接近的三个点
|
||
def GetClosestThree(x, list_x):
|
||
"""
|
||
获取与待求点 x 最接近的三个插值点的索引。
|
||
|
||
参数:
|
||
x (float): 待插值的自变量值。
|
||
list_x (list of float): 自变量列表,要求已按升序排列。
|
||
|
||
返回:
|
||
tuple of int: 最接近的三个点的索引 (i, j, k),满足 list_x[i] <= x < list_x[k]。
|
||
"""
|
||
if x < list_x[1]:
|
||
return 0, 1, 2
|
||
for i in range(3, len(list_x)):
|
||
if x < list_x[i]:
|
||
return i-2, i-1, i
|
||
return len(list_x)-3, len(list_x)-2, len(list_x)-1
|
||
|
||
# 线性插值余项计算
|
||
def LinearRegression(x, list_x):
|
||
"""
|
||
计算线性插值的余项估计值。
|
||
|
||
参数:
|
||
x (float): 待插值的自变量值。
|
||
list_x (list of float): 自变量列表,要求已按升序排列。
|
||
|
||
返回:
|
||
float: 线性插值的余项估计值。
|
||
"""
|
||
i, j = GetClosestTwo(x, list_x)
|
||
ks = max([abs(FxDiff_n(list_x[i], 2)), abs(FxDiff_n(list_x[j], 2))]) # 二阶导数的最大值
|
||
omg = (x - list_x[i]) * (x - list_x[j]) # 乘积项
|
||
return abs(ks * omg / 2)
|
||
|
||
# 抛物线插值余项计算
|
||
def ParabolaRegression(x, list_x):
|
||
"""
|
||
计算抛物线插值的余项估计值。
|
||
|
||
参数:
|
||
x (float): 待插值的自变量值。
|
||
list_x (list of float): 自变量列表,要求已按升序排列。
|
||
|
||
返回:
|
||
float: 抛物线插值的余项估计值。
|
||
"""
|
||
i, j, k = GetClosestThree(x, list_x)
|
||
ks = max([abs(FxDiff_n(list_x[i], 3)), abs(FxDiff_n(list_x[j], 3)), abs(FxDiff_n(list_x[k], 3))]) # 三阶导数的最大值
|
||
omg = (x - list_x[i]) * (x - list_x[j]) * (x - list_x[k]) # 乘积项
|
||
return abs(ks * omg / 6)
|
||
|
||
# 线性插值
|
||
def LinearInterpolation(x, list_x, list_y):
|
||
"""
|
||
使用线性插值法计算插值结果及其余项估计值。
|
||
|
||
参数:
|
||
x (float): 待插值的自变量值。
|
||
list_x (list of float): 自变量列表,要求已按升序排列。
|
||
list_y (list of float): 因变量列表,与 list_x 一一对应。
|
||
|
||
返回:
|
||
tuple: 插值结果和余项估计值 (result, r)。
|
||
"""
|
||
i, j = GetClosestTwo(x, list_x)
|
||
result = list_y[i] + (x - list_x[i]) * (list_y[j] - list_y[i]) / (list_x[j] - list_x[i]) # 插值公式
|
||
r = LinearRegression(x, list_x) # 余项估计
|
||
return (result, r)
|
||
|
||
# 抛物线插值
|
||
def ParabolaInterpolation(x, list_x, list_y):
|
||
"""
|
||
使用抛物线插值法计算插值结果及其余项估计值。
|
||
|
||
参数:
|
||
x (float): 待插值的自变量值。
|
||
list_x (list of float): 自变量列表,要求已按升序排列。
|
||
list_y (list of float): 因变量列表,与 list_x 一一对应。
|
||
|
||
返回:
|
||
tuple: 插值结果和余项估计值 (result, r)。
|
||
"""
|
||
i, j, k = GetClosestThree(x, list_x)
|
||
result = list_y[i] * (x - list_x[j]) * (x - list_x[k]) / (list_x[i] - list_x[j]) / (list_x[i] - list_x[k])
|
||
result += list_y[j] * (x - list_x[i]) * (x - list_x[k]) / (list_x[j] - list_x[i]) / (list_x[j] - list_x[k])
|
||
result += list_y[k] * (x - list_x[i]) * (x - list_x[j]) / (list_x[k] - list_x[i]) / (list_x[k] - list_x[j])
|
||
r = ParabolaRegression(x, list_x) # 余项估计
|
||
return (result, r)
|
||
|
||
# 拉格朗日插值
|
||
def LagrangeInterpolation(x, list_x, list_y):
|
||
"""
|
||
使用拉格朗日插值法计算插值结果。
|
||
|
||
参数:
|
||
x (float): 待插值的自变量值。
|
||
list_x (list of float): 自变量列表,要求已按升序排列。
|
||
list_y (list of float): 因变量列表,与 list_x 一一对应。
|
||
|
||
返回:
|
||
float: 插值结果。
|
||
"""
|
||
result = 0
|
||
for i in range(0, len(list_x)):
|
||
temp = 1
|
||
for j in range(0, len(list_x)):
|
||
if i != j:
|
||
temp *= (x - list_x[j]) / (list_x[i] - list_x[j]) # 拉格朗日基函数
|
||
result += temp * list_y[i]
|
||
return result
|
||
|
||
if __name__ == "__main__":
|
||
# 测试线性插值
|
||
print(LinearInterpolation(11.75, list_x, list_y))
|
||
# 测试抛物线插值
|
||
print(ParabolaInterpolation(11.75, list_x, list_y))
|
||
# 测试拉格朗日插值
|
||
print(LagrangeInterpolation(11.75, list_x, list_y))
|