这里不介绍牛顿插值多项式数学推导,只提供Python循环和递归实现的思路与代码,想要学习牛顿插值多项式的同学可以去看数值分析课本等。
这里提供循环和递归两种思路,因为我是先想的递归,完整的代码和思路都有,循环只有思路和部分关键代码。循环写在前面是因为循环更容易理解。
牛顿插值多项式由n阶差商和已知点的y值构成。
我们想要构造牛顿插值多项式,就要先构造差商表,有了差商表就有了所有差商,再结合y值就可以构造式子。
第一个想到的方法是构造一个数组,利用循环计算每个n阶差商(比如一阶差商、二阶差商、三阶差商)。循环的内容是计算差商并填入数组中,因为差商计算有规律可循,直接对照差商表的位置(即每个数的角标)算即可。
这种方法是利用已知数据的差商表逆推计算规律,利用计算规律写代码通式。
构造差商表:
这里给出一个例子:
x | y | 一阶差商 | 二阶差商 | 三阶差商 | 四阶差商 |
1 | 1 | ||||
2 | 4 | a1=3 | |||
3 | 7 | a2=3 | b1=0 | ||
4 | 8 | a3=1 | b2=-1 | c1= | |
5 | 6 | a4=-2 | b3= | c2= | d1= |
上表中已知五个点的x、y值,需要求a1、a2、a3、a4,b1、b2、b3,c1、c2,d1。(构造牛顿插值多项式时只需要a1、b1、c1、d1即可,但求b1需要用到a1、a2,求c1需要用到b1、b2,求d1需要用到c1、c2。不懂为什么的话就去看看数学式子吧٩(๑>₃<)۶ )
我们要构建一个5*6的数组(也可以构建6*6的数组跟上表一样,5*6的数组不包括第一行表头),先算a1,a1=(4-1)/(2-1),出现的数字按照先后顺序,4是第二个y值,1是第一个y值,2是第二个x值,1是第一个x值。
同理,a2=(7-4)/(3-2),a3=(8-7)/(4-3),a4=(6-8)/(5-4)
a的计算规律我们找到了,分子分母分开来看,分子是对应行y值-上一行y值,分母是对应行x值-上一行x值。
但b的计算规律也是这样吗?
由表找规律发现不一样,c的计算规律与a、b也不一样。我建议大家可以花时间找一找,规律与n阶差商的n有关。
找出来了吗,我这里直接说了:
某一个要求的值=(左边值-左上值)/(同行x值-(当前行-n行的x值))
如b1=(a2-a1)/(3-1),b3=(a4-a3)/(5-3)
规律都找到了,可以写代码通式了。
代码实现
这里我只给出部分核心代码,因为我没写。
x[i][j]=x[i][j-1]-x[i-1][j-1]/x[i][0]-x[i-n][0]
其中x为构建的数组x,x[i][j]代表要求的位置的数,n为n阶差商的n。
剩下的就是利用循环不断地算不同位置的数啦!你一定会吧!(>ω・* )ノ
构建牛顿插值多项式
根据数学公式可以构建,简单解释为:
多项式=从第一个y值开始,对角线上的数值分别连乘(x-比它高的行的x)
即P(x)=1+3*(x-1)+0*(x-1)(x-2)+()*(x-1)(x-2)(x-3)+*(x-1)(x-2)(x-3)(x-4)
代码实现也是利用循环构造乘法和加法,这里我就不写了因为我没写。可以参考下面第二种方法里构造多项式的代码,也是利用循环构造乘法和加法,思路是一样的,聪明的你看看一定能自己写出来!
递归的思路是根据数学公式来的,找数学公式的规律构造代码通式。
x | y | 一阶差商 | 二阶差商 | 三阶差商 | 四阶差商 |
1 | 1 | ||||
2 | 4 | a1=3 | |||
3 | 7 | a2=3 | b1=0 | ||
4 | 8 | a3=1 | b2=-1 | c1= | |
5 | 6 | a4=-2 | b3= | c2= | d1= |
还是这个表,我列出几个算差商的数学公式:
简单来说分子和分母之间是交叉互补的关系(仅限表面数字互补,没有实际含义)
以下我们用k表示k阶差商里的阶数,点x的值放到一个列表里,列表x里的值角标为0、1、2...n
我们发现分母就是n-(n-1),分子是k-1阶差商相减,第一个差商是1、2...n-2、n的差商,第二个差商是1、2...n-2、n-1的差商。(第一个少n-1,第二个少n)
根据这个规律我们就可以构造递归式,代码如下:
#构建点坐标的x值列表和y值列表
x=[1,2,3,4,5]
y=[1,4,7,8,6]
#定义求差商得函数
def chashang(k,a,n):
#k代表k阶差商,a代表倒数第二位角标,n代表最后一位角标。
if k==1:
cs=(y[n]-y[a])/(x[n]-x[a])
return cs
else:
cs=(chashang(k-1,a-1,n)-chashang(k-1,a-1,a))/(x[n]-x[a])
return cs
以上为关键阶差商求法(关键阶差商指对角线上的差商,如a1、b1、c1、d1),也可以把所有差商都保存下来,但没必要,因为构建多项式不需要所有差商,只需要关键阶差商,就没加保存数据代码。
这串代码只能求阶k与数角标n相等的情况,比如求(三阶012),(四阶0123).不能差着求比如(三阶023)(这个在递归式里计算机自动求了,但没法直接利用函数先求)。如果想求三阶023这种非对角线差商,可以在代码里加一个保存数据的代码保存到数组里,这样所有差商都有了。
有了差商,再根据已知的y值就可以构造多项式了。
构造牛顿插值多项式
利用循环不断改变n与k的取值,就可以构造多项式里连乘和连加的效果,代码如下:
for n in range(len(x)):
if n==0:
ND=y[0]
continue
else:
a=n-1
k=n
Niudun=chashang(k,a,n)
for i in range(n):
Niudun=Niudun*(b-x[i])
ND=ND+Niudun
这样牛顿插值多项式就构造完成了,只需要一个获取想要预测的x值的代码就可以了!这里我用的
b=eval(input('请输入x坐标:'))
这个要放在循环构建多项式的前面,因为循环构建多项式的代码需要用到b这个参数。
最后我再放一个整体的代码供大家参考:
x=[1,2,3,4,5]
y=[1,4,7,8,6]
def chashang(k,a,n):
#k代表k阶差商,a代表倒数第二位角标,n代表最后一位角标。
if k==1:
cs=(y[n]-y[a])/(x[n]-x[a])
return cs
else:
cs=(chashang(k-1,a-1,n)-chashang(k-1,a-1,a))/(x[n]-x[a])
return cs
#以上为关键阶求法,也可以把整个差商表保存下来,但没必要,就没加保存数据代码。
#以下为利用循环构建牛顿插值多项式
b=eval(input('请输入x坐标:'))
for n in range(len(x)):
if n==0:
ND=y[0]
continue
else:
a=n-1
k=n
Niudun=chashang(k,a,n)
for i in range(n):
Niudun=Niudun*(b-x[i])
ND=ND+Niudun
print(ND)