牛顿插值¶
Ⅰ. 作用 –> Ⅱ. 原理 –> Ⅲ. 余项 –> Ⅳ. 示例 –> Ⅴ. Python 代码
Ⅰ. 作用¶
牛顿插值是根据已知点列,构造插值多项式,用多项式预测新节点的函数值. 这和拉格朗日插值作用一致,但牛顿插值可以避免拉氏插值的一个弊端:拉格朗日插值节点增加或减少,拉格朗日多项式需要全部重新计算,虽然对计算机而言无所畏惧,但肯定还是不便的,会带来资源开销,牛顿插值能够解决这种增减带来全部计算的现象. 牛顿插值和拉格朗日插值本质上都是多项式插值法,牛顿插值法与拉格朗日插值法相比具有承袭性和易于变动的特点【继承和易变,后面示例部分可以体悟】.
Ⅱ. 原理¶
USTC 的幻灯片(http://staff.ustc.edu.cn/~rui/ppt/num/num-interpolation-newton.html)更详尽地阐述牛顿插值法.
已知一系列从小到大排序(自变量排序而非因变量)互不相同的 个节点:
定义牛顿插值多项式:
阶数: .
多项式系数,即均差:
Ⅲ. 余项¶
牛顿插值的误差本质上同拉格朗日插值余项:
可以把 看作
处理, 由于均差具有任意交换性:
那么,因为 是自变量,所以,
要看作已知点列,
看作自变量.
Ⅳ. 示例¶
为了计算牛顿插值多项式各系数,列出包含所有系数的均差表,无论从手动笔算角度还是计算机运算角度,都是明智的抉择.
x |
y |
一阶 |
二阶 |
三阶 |
四阶 |
|---|---|---|---|---|---|
我们需要的系数就是均差表主对角线元素.
计算已知点列的牛顿插值法在 处的函数值:
x |
y |
一阶 |
二阶 |
三阶 |
|---|---|---|---|---|
(-4-0)/[0-(-1)]=-4 |
||||
[-2-(-4)]/(1-0)=2 |
[2-(-4)]/[1-(-1)]=3 |
|||
[5-(-2)]/(2-1)=7 |
(7-2)/(2-0)=2.5 |
(2.5-3)/[2-(-1)]=-1/6 |
则三次牛顿插值多项式为:
继承和易变是牛顿插值法的特点,牛顿插值多项式的基底是:
当每次增加(或减少)一个节点,只需要补充(或删除)一个均差系数与基底的乘积项即可,不必大动干戈重新计算多项式,这就是牛顿插值相比于拉格朗日插值的一个改进.
Ⅴ. 代码¶
1'''
2# System --> Windows & Python3.8.0
3# File ----> NewtonInterpolation.py
4# Author --> Illusionna
5# Create --> 2024/2/15 23:28:36
6'''
7# -*- Encoding: UTF-8 -*-
8
9
10import numpy as np
11import pandas as pd
12
13
14class NEWTON_INTERPOLATION:
15 """
16 牛顿插值类.
17 """
18 def __init__(self, *args, X:list, Y:list, **kwargs) -> None:
19 """
20 初始化构造函数: 传入已知点列.
21 """
22 self.__X = X
23 self.__Y = Y
24 self.coefficients = [Y[0]]
25 if ((len(self.__X) <= 1) | (len(self.__Y) <= 1)) | (len(self.__X) != len(self.__Y)):
26 assert print(f'输入点列\033[31m X 长度: {len(self.__X)}, Y 长度: {len(self.__Y)},\033[0m 已知点列数量过短或长度不一致.')
27 self.__Create()
28
29 def CalculateDividedDifferences(self) -> None:
30 """
31 公有函数: 计算均差表.
32 """
33 pos = 1
34 for i in range(0, len(self.__X)-1, 1):
35 for j in range(0, len(self.__Y)-1, 1):
36 x = self.__X[j+pos] - self.__X[j]
37 y = self.__Y[j+1] - self.__Y[j]
38 self.__Y.append(y/x)
39 self.__dividedDifferencesTable[j+pos][i+2] = y/x
40 del self.__Y[:(len(self.__X)-i)]
41 pos = -~pos
42 self.coefficients.append(self.__Y[0])
43
44 def __Create(self) -> None:
45 """
46 私有函数: 创建初始化的均差表.
47 """
48 self.__dividedDifferencesTable = np.ones([len(self.__X), len(self.__X)+1]) * np.inf
49 tmp = np.array([self.__X]).T
50 self.__dividedDifferencesTable[:,[0]] = tmp
51 tmp = np.array([self.__Y]).T
52 self.__dividedDifferencesTable[:,[1]] = tmp
53
54 def __Base(self) -> None:
55 """
56 私有函数: 生成多项式基底.
57 """
58 self.base = ['1']
59 for i in range(0, len(self.__X), 1):
60 value = ''
61 for j in range(0, i, 1):
62 if self.__X[j] >= 0:
63 tmp = f'(x-{self.__X[j]})'
64 else:
65 tmp = f'(x+{-self.__X[j]})'
66 value = value + tmp
67 if len(value) != 0:
68 self.base.append(value)
69
70 def Interpolate(self, x:float) -> float:
71 """
72 公有函数: 牛顿插值, 输入插值节点, 返回插值.
73 """
74 result = 1*self.coefficients[0]
75 tmp = 1
76 for index in range(0, len(self.__X)-1, 1):
77 value = x - self.__X[index]
78 tmp = tmp * value
79 result = result + tmp * self.coefficients[index+1]
80 return result
81
82 def Information(self) -> None:
83 """
84 公有函数: 打印信息.
85 """
86 self.__Base()
87 if len(self.coefficients) <= 12:
88 tmp = pd.DataFrame(self.__dividedDifferencesTable)
89 print(f'均差表:\n{tmp}\n')
90 print(f'牛顿插值法的基底:\n{self.base}\n')
91 print(f'牛顿插值多项式系数(\033[34mcoefficients\033[0m):\n{self.coefficients}\n')
92 else:
93 print(f'\033[33m均差表维度 {self.__dividedDifferencesTable.shape[0]}x{self.__dividedDifferencesTable.shape[1]} 过大, 不易打印.\033[0m')
94 print(f'牛顿插值法的基底:\n{self.base}\n')
95 print(f'牛顿插值多项式系数(\033[34mcoefficients\033[0m):\n{self.coefficients}\n')
96
97
98if __name__ == '__main__':
99 X = [-1, 0, 1, 2]
100 Y = [0, -4, -2, 5]
101
102 obj = NEWTON_INTERPOLATION(X=X, Y=Y)
103 obj.CalculateDividedDifferences()
104 obj.Information()
105 print(f'预测函数值: {obj.Interpolate(x=1.5)}')
插值结果: