牛顿插值多项式 Python 循环和递归两种实现思路

这里不介绍牛顿插值多项式数学推导,只提供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=\tiny -\frac{1}{3}
5 6 a4=-2 b3=\tiny -\frac{3}{2} c2=\tiny -\frac{1}{6} d1=\tiny \frac{1}{24}

上表中已知五个点的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)+(\tiny -\frac{1}{3})*(x-1)(x-2)(x-3)+\tiny \frac{1}{24}*(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=\tiny -\frac{1}{3}
5 6 a4=-2 b3=\tiny -\frac{3}{2} c2=\tiny -\frac{1}{6} d1=\tiny \frac{1}{24}

还是这个表,我列出几个算差商的数学公式:

f[1,2]=\frac{4-1}{2-1}

f[2,3]=\frac{7-4}{3-2}

f[3,4]=\frac{8-7}{4-3}

f[4,5]=\frac{6-8}{5-4}

f[1,2,3]=\frac{f[1,3]-f[1,2]]}{3-2}

f[2,3,4]=\frac{f[2,4]-f[2,3]}{4-3}

 f[3,4,5]=\frac{f[3,5]-f[3,4]}{5-4}

f[1,2,3,4]=\frac{f[1,2,4]-f[1,2,3]}{4-3}

简单来说分子和分母之间是交叉互补的关系(仅限表面数字互补,没有实际含义)

以下我们用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相等的情况,比如求f[0,1,2](三阶012),f[0,1,2,3](四阶0123).不能差着求比如f[0,2,3](三阶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)

你可能感兴趣的:(算法,python)