Python模擬Lagrange插值結果並分析誤差

Python模擬Lagrange插值代碼及結果

題目:exp(x)(函數可變)在[0,4]的n階多項式插值及誤差

思路

主要思路分爲兩部分:

  1. 如何計算n階多項式插值?
  2. 誤差如何計算?

首先第一個部分:
對於lagrange插值函數的計算,首先我們觀察公式:
Ln(x)=k=0nyklk(x)L_n(x)=\sum\limits_{k=0}^n y_k l_k(x)
其中,lk(x)=(xx0)(xxk1)(xxk+1)(xkxn)(xkx0)(xkxk1)(xkxk+1)(xkxn)l_k(x)=\frac{(x-x_0)\dots(x-x_{k-1})(x-x_{k+1})\dots(x_k-x_n)}{(x_k-x_0)\dots(x_k-x_{k-1})(x_k-x_{k+1})\dots(x_k-x_n)}
公式寫在代碼中就是連乘,並且需要循環嵌套。並且當分母爲零(相減兩項相同時),乘式應爲1。
第二個部分更加簡單,這裏的誤差我們取絕對誤差,即爲解析值-真值。需要考慮的是誤差的變化。需要觀察兩種情況:固定插值次數,變換x看誤差變化;固定x,增加插值次數看誤差變化。

代碼部分

#exp(x)在[0,4]的n階多項式插值及誤差
import math
import numpy as np
import matplotlib.pyplot as plt

def truev(x): 
    a=np.sin(x)
    return a

#計算n+1個真值
def truex(x0,xn,n):
    v = np.zeros((n+1,2))#開闢一個數組存x以及對應的y值
    h = (xn-x0)/n#步長
    for i in range(n+1):
        v[i][0]= x0+(h * i)
        v[i][1]=truev(v[i][0])
    return v;

def truearrayx(x0,xn):
    h=0.001;
    o=int((xn-x0)/h)
    m = np.zeros((o,2))
    s = np.zeros(o)
    z = np.zeros(o)
    #print(m);#開闢一個數組存x以及對應的y值
    for i in range(o):
        s[i]= x0+(h * i)
            #print(x[i])
        z[i]=truev(s[i]) 
    return s,z

def Lagrangev(x0,xn,arr,n,t):#輸入值:存放真值的數組、插值次數;輸出值:函數結果
    p=0
    l=np.zeros(n+1)
    d=np.zeros(n+1)
    if (((t-x0)*n)%(xn-x0)==0 ):#取端點值得真值
        t=int(((t-x0)*n)/(xn-x0))
        print(t)
        p=arr[t][1]
    else:
        for j in range(n+1):
            l[j]=arr[j][1]
            for k in range(n+1):
                if(arr[j][0]-arr[k][0]==0):
                    d[k]=1
                    l[j]=l[j]
                else:
                    d[k]=arr[j][0]-arr[k][0]
                    l[j]=l[j]*(t-arr[k][0])/(d[k])
        for j in range(n+1):
            p=p+l[j]#求和
    return p



def lagrangarrayx(x0,xn,arr,n):
    g = np.zeros(n+1)
    f = np.zeros(n+1)
    h=(xn-x0)/n
    for i in range(n+1):
        g[i]= x0+(h * i)
        f[i]=Lagrangev(x0,xn,arr,n,g[i])
    return g,f


def errorx(x0,xn,n,x):#輸入起始值;終值;插值次數;x值
    b=truex(x0,xn,n)
    a=Lagrangev(x0,xn,b,n,x)
    c=truev(x)
    errorv=a-c
    return errorv


#畫圖:誤差曲線;問題,x應該取何值?將x軸離散化求值,而且要把error爲0的點避開
def errorarrayx(x0,xn,n):
    h=(xn-x0)/n
    m = np.zeros((n,2))
    u = np.zeros(n)
    r = np.zeros(n)
    for i in range(n):
        m[i][0]= x0+(h * i)
        u[i]=m[i][0]
        m[i][1]=errorx(x0,xn,n,m[i][0])
        r[i]=m[i][1]
    return u,r

x0=0;xn=4;n1=8;n=4;h=(xn-x0)/n
e=truex(x0,xn,n)
e1=truex(x0,xn,n1)
(a,b)=truearrayx(x0,xn)
(c,d)=lagrangarrayx(x0,xn,e,n)
(c1,d1)=lagrangarrayx(x0,xn,e1,n1)
fig = plt.figure(num=1, figsize=(30, 15),dpi=80) 

plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False#設置漢語顯示
plt.plot(a,b, label='true values', linewidth=4, color='fuchsia')
plt.plot(c,d, label='n=4 Lagrange interpolation', linewidth=3, color='lawngreen', marker='o',
         markerfacecolor='beige', markersize=6)
plt.plot(c1,d1, label='n=8 Lagrange interpolation', linewidth=3, color='cyan', marker='o',
         markerfacecolor='coral', markersize=6)

for x, y in zip(c, d):
    plt.text(x, y, y, ha='center', va='bottom', fontsize=10,rotation=5)
for x1, y1 in zip(c1, d1):
    plt.text(x1, y1, y1, ha='center', va='bottom', fontsize=10,rotation=5)
plt.legend(loc="upper right",fontsize="xx-large")
plt.xlabel("x")
plt.ylabel("Values")

plt.title('Result Of Lagrange Interpolation ',fontsize='xx-large',fontweight='black')
plt.show()

代碼運行結果

sin(x)sin(x)插值n=4;n=8結果:
在這裏插入圖片描述

cos(x)cos(x)插值n=4;n=8結果:
在這裏插入圖片描述
exe^x插值n=4;n=8結果:
在這裏插入圖片描述

分析誤差

對於同一n(假設爲8)不同的x

代碼如下:

#誤差曲線
fig = plt.figure(num=1, figsize=(30, 15),dpi=150)
(a,b)=errorarrayx(0,4,8)
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False#設置漢語顯示
plt.plot(a,b, label=' error of n=20 Lagrange interpolation',  linewidth=3, color='red', marker='o',
         markerfacecolor='blue', markersize=6)
for x, y in zip(a,b):
    plt.text(x, y, y, ha='center', va='bottom', fontsize=6)
plt.xlabel("x")
plt.ylabel("Error")

plt.title('Error Of Lagrange Interpolation with different x ',fontsize='xx-large',fontweight='black')
plt.show()

結果

在這裏插入圖片描述

對於同一x(固定取3.44),取不同n

代碼如下:

#誤差曲線
fig = plt.figure(num=1, figsize=(30, 15),dpi=150)
#(a,b)=errorarrayx(0,4,8)
b=errorarrayn(0,4,3.44,19)#輸入n取值的最大值
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False#設置漢語顯示
# plt.plot(a,b, label=' error of n=20 Lagrange interpolation',  linewidth=3, color='red', marker='o',
#          markerfacecolor='blue', markersize=6)
# for x, y in zip(a,b):
#     plt.text(x, y, y, ha='center', va='bottom', fontsize=6)
# plt.xlabel("x")
# plt.ylabel("Error")

# plt.title('Error Of Lagrange Interpolation with different x ',fontsize='xx-large',fontweight='black')
plt.plot(range(20),b, label=' error of n=20 Lagrange interpolation',  linewidth=3, color='red', marker='o',
         markerfacecolor='blue', markersize=6)
for x, y in zip(range(20),b):
    plt.text(x, y, y, ha='center', va='bottom', fontsize=6,rotation=10)
plt.xlabel("n")
plt.ylabel("Error")

plt.title('Error Of Lagrange Interpolation with different n ',fontsize='xx-large',fontweight='black')
plt.show()

結果

在這裏插入圖片描述

Problem

當x靠近端點值(eg:取x=3.98),n增大到一定程度時,會出現所謂的龍格現象。如下圖所示:
在這裏插入圖片描述

龍格現象:

一般情況下,多項式的次數越多,需要的數據就越多,而預測也就越準確。插值次數越高,插值結果越偏離原函數的現象稱爲龍格現象。

插值結果及誤差分析

由上述圖中我們可以發現:

  • 拉格朗日插值函數比較接近原函數;
  • 固定n,誤差隨x值變化沒有什麼規律。有幾個插值節點,誤差就有幾個零點。在零點周圍,誤差有正有負;
  • 固定x,誤差隨着n值的增大越來越小。插值次數增加到一定程度,會產生龍格現象。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章