R语言实现牛顿插值

文章目录

    • 4 差商与牛顿插值
      • 差商
      • 牛顿插值

4 差商与牛顿插值

差商

如果采取间隔不等的采样,差商会变得稍显复杂,对于 x 0 , x 1 , … , x n x_0,x_1,\ldots,x_n x0,x1,,xn,若与 y 0 , y 1 , … , y n y_0,y_1,\ldots,y_n y0,y1,,yn通过映射 f f f一一对应,则定义比值

f [ x 0 , x 1 ] = f ( x 1 ) − f ( x 0 ) x 1 − x 0 f[x_0,x_1]=\frac{f(x_1)-f(x_0)}{x_1-x_0} f[x0,x1]=x1x0f(x1)f(x0)

f ( x ) f(x) f(x)关于节点 x 0 , x 1 x_0,x_1 x0,x1的一阶差商。

由于在计算二阶差商的时候,不可避免地涉及到3个点,所以二阶差商定义为

f [ x 0 , x 1 , x 2 ] = f [ x 0 , x 2 ] − f [ x 0 , x 1 ] x 2 − x 1 f[x_0,x_1,x_2]=\frac{f[x_0,x_2]-f[x_0,x_1]}{x_2-x_1} f[x0,x1,x2]=x2x1f[x0,x2]f[x0,x1]

k k k阶差商定义为

f [ x 0 , x 1 , … , x k ] = f [ x 0 , x 1 , … , x k − 2 , x k ] − f [ x 0 , x 1 , … , x k − 1 ] x k − x k − 1 f[x_0,x_1,\ldots,x_k]=\frac{f[x_0,x_1,\ldots,x_{k-2},x_k]-f[x_0,x_1,\ldots,x_{k-1}]}{x_k-x_{k-1}} f[x0,x1,,xk]=xkxk1f[x0,x1,,xk2,xk]f[x0,x1,,xk1]

若将 k k k阶差商展开,则可表示为函数值 f ( x 0 ) , f ( x 1 ) , … , f ( x k ) f(x_0),f(x_1),\ldots,f(x_k) f(x0),f(x1),,f(xk)的线性组合,且每一项的分母必可写为 k k k x i − x j x_i-x_j xixj的乘积,可以表示为

f [ x 0 , x 1 , … , x k ] = ∑ j = 0 k f ( x j ) ( x j − x 0 ) … ( x j − x j − 1 ) ( x j − x j + 1 ) … ( x j − x k ) f[x_0,x_1,\ldots,x_k]=\displaystyle\sum_{j=0}^k\frac{f(x_j)}{(x_j-x_0)\ldots(x_j-x_{j-1})(x_j-x_{j+1})\ldots(x_j-x_k)} f[x0,x1,,xk]=j=0k(xjx0)(xjxj1)(xjxj+1)(xjxk)f(xj)

其中第 j j j项的分母中不存在 x j − x j x_j-x_j xjxj。则

f [ x 0 , … , x k − 1 ] = ∑ j = 0 k − 1 f ( x j ) ( x j − x 0 ) … ( x j − x j − 1 ) ( x j − x j + 1 ) … ( x j − x k − 1 ) f [ x 1 , … , x k ] = ∑ j = 1 k f ( x j ) ( x j − x 1 ) … ( x j − x j − 1 ) ( x j − x j + 1 ) … ( x j − x k ) \begin{aligned} f[x_0,\ldots,x_{k-1}]&=\displaystyle\sum_{j=0}^{k-1}\frac{f(x_j)}{(x_j-x_0)\ldots(x_j-x_{j-1})(x_j-x_{j+1})\ldots(x_j-x_{k-1})}\\ f[x_1,\ldots,x_k]&=\displaystyle\sum_{j=1}^{k}\frac{f(x_j)}{(x_j-x_1)\ldots(x_j-x_{j-1})(x_j-x_{j+1})\ldots(x_j-x_{k})} \end{aligned} f[x0,,xk1]f[x1,,xk]=j=0k1(xjx0)(xjxj1)(xjxj+1)(xjxk1)f(xj)=j=1k(xjx1)(xjxj1)(xjxj+1)(xjxk)f(xj)

易得

f [ x 0 , x 1 , … , x k ] = f [ x 1 , x 2 , … , x k ] − f [ x 0 , x 1 , … , x k − 1 ] x k − x 0 f[x_0,x_1,\ldots,x_k]=\frac{f[x_1,x_2,\ldots,x_k]-f[x_0,x_1,\ldots,x_{k-1}]}{x_k-x_0} f[x0,x1,,xk]=xkx0f[x1,x2,,xk]f[x0,x1,,xk1]

根据这个表达式,可以通过一个简单的递归程序计算数组的差商

# 差商算法,x,y为同等长度的数组
diffDiv<-function(x,y){
    end = length(x)
    ind = 2:end #索引
    return(
        if(end==1) y[1]
        else (diffDiv(x[ind],y[ind])
            -diffDiv(x[ind-1],y[ind-1]))/(x[end]-x[1])
    )
}

如果要计算阶数为k的差商,只需重复调用diffDiv

kDiffDiv <- function(x,y,k){
    len <- length(x)
    if(len<k) return(0)
    d<-rep(0,len-k)
    for(i in 1:(len-k))
        d[i] <- diffDiv(x[i:(i+k)],y[i:(i+k)])
    return(d)
}

据此,绘制出 y = x 5 y=x^5 y=x5这个函数的差商,

> plot(x,y)
> k = 1
> lines(x[1:(end-k)],kDiffDiv(x,y,k),col="red")
> k = 2
> lines(x[1:(end-k)],kDiffDiv(x,y,k),col="green")
> k = 3
> lines(x[1:(end-k)],kDiffDiv(x,y,k),col="blue")
> k = 4
> lines(x[1:(end-k)],kDiffDiv(x,y,k),col="purple")
> k = 5
> lines(x[1:(end-k)],kDiffDiv(x,y,k),col="yellow")
> k = 6
> lines(x[1:(end-k)],kDiffDiv(x,y,k),col="gray")

如图所示

R语言实现牛顿插值_第1张图片

牛顿插值

可见差商与微分在阶数上有着一致的趋势。那么,知道了差商之后,可以做点什么呢?

根据差商定义,可得

f ( x ) = f ( x 0 ) + f [ x , x 0 ] ( x − x 0 ) f [ x , x 0 ] = f [ x 0 , x 1 ] + f [ x , x 0 , x 1 ] ( x − x 1 ) ⋮ f [ x , x 0 , … , x n − 1 ] = f [ x 0 , x 1 , … , x n ] + f [ x , x 0 , x 1 , … , x n ] ( x − x n ) \begin{aligned} f(x) &= f(x_0) + f[x,x_0](x-x_0)\\ f[x,x_0] &= f[x_0,x_1] + f[x,x_0,x_1](x-x_1)\\ &\vdots\\ f[x,x_0,\ldots,x_{n-1}] &= f[x_0,x_1,\ldots,x_n] + f[x,x_0,x_1,\ldots,x_n](x-x_n) \end{aligned} f(x)f[x,x0]f[x,x0,,xn1]=f(x0)+f[x,x0](xx0)=f[x0,x1]+f[x,x0,x1](xx1)=f[x0,x1,,xn]+f[x,x0,x1,,xn](xxn)

可见,通过差商可以逼近函数的真实值,将上式合并可得

f ( x ) = f ( x 0 ) + f [ x 0 , x 1 ] ( x − x 0 ) + f [ x 0 , x 1 , x 2 ] ( x − x 0 ) ( x − x 1 ) + … + f [ x 0 , x 1 , … , x n ] ( x − x 0 ) ( x − x 1 ) … ( x − x n − 1 ) + f [ x 0 , x 1 , … , x n ] ω n + 1 ( x ) = N n ( x ) + R n ( x ) \begin{aligned} f(x) =& f(x_0) + f[x_0,x_1](x-x_0)+ f[x_0,x_1,x_2](x-x_0)(x-x_1)\\ &+\ldots+f[x_0,x_1,\ldots,x_n](x-x_0)(x-x_1)\ldots(x-x_{n-1})\\ &+f[x_0,x_1,\ldots,x_n]\omega_{n+1}(x)\\ =&N_n(x)+R_n(x) \end{aligned} f(x)==f(x0)+f[x0,x1](xx0)+f[x0,x1,x2](xx0)(xx1)++f[x0,x1,,xn](xx0)(xx1)(xxn1)+f[x0,x1,,xn]ωn+1(x)Nn(x)+Rn(x)

其中,

N n ( x ) = f ( x 0 ) + f [ x 0 , x 1 ] ( x − x 0 ) + f [ x 0 , x 1 , x 2 ] ( x − x 0 ) ( x − x 1 ) + … + f [ x 0 , x 1 , … , x n ] ( x − x 0 ) ( x − x 1 ) … ( x − x n − 1 ) R n ( x ) = f [ x 0 , x 1 , … , x n ] ω n + 1 ( x ) \begin{aligned} N_n(x) =& f(x_0) + f[x_0,x_1](x-x_0)+ f[x_0,x_1,x_2](x-x_0)(x-x_1)+\\ &\ldots+f[x_0,x_1,\ldots,x_n](x-x_0)(x-x_1)\ldots(x-x_{n-1})\\ R_n(x)=&f[x_0,x_1,\ldots,x_n]\omega_{n+1}(x) \end{aligned} Nn(x)=Rn(x)=f(x0)+f[x0,x1](xx0)+f[x0,x1,x2](xx0)(xx1)++f[x0,x1,,xn](xx0)(xx1)(xxn1)f[x0,x1,,xn]ωn+1(x)

其中, ω n + 1 ( x ) = ( x − x 0 ) ( x − x 1 ) … ( x − x n ) \omega_{n+1}(x)=(x-x_0)(x-x_1)\ldots(x-x_n) ωn+1(x)=(xx0)(xx1)(xxn) N n ( x ) N_n(x) Nn(x)就是大名鼎鼎的牛顿插值公式,其是一种十分强大的插值算法,递推式可以写为

N n + 1 ( x ) = N n ( x ) + f [ x 0 , x 1 , … , x n + 1 ] ω n + 1 ( x ) N_{n+1}(x) = N_{n}(x) + f[x_0,x_1,\ldots,x_{n+1}]\omega_{n+1}(x) Nn+1(x)=Nn(x)+f[x0,x1,,xn+1]ωn+1(x)

由于牛顿插值的本质是多项式插值,所以关键是得到插值多项式的系数。记 N n , i N_{n,i} Nn,i n n n阶牛顿多项式的第 i i i项,记 ω n , i \omega_{n,i} ωn,i n n n ω \omega ω多项式的第 i i i项,则其递推式可以写为

N n ( x ) = ∑ i = 0 n N n , i x i = ∑ i = 0 n − 1 N n − 1 , i x i + f [ x 0 , x 1 , … , x n ] ∑ i = 0 n ω n , i x i N_n(x)=\sum_{i=0}^{n}N_{n,i}x^i=\sum_{i=0}^{n-1}N_{n-1,i}x^i + f[x_0,x_1,\ldots,x_n]\sum_{i=0}^{n}\omega_{n,i}x^i Nn(x)=i=0nNn,ixi=i=0n1Nn1,ixi+f[x0,x1,,xn]i=0nωn,ixi

∑ i = 0 n N n , i x i = ∑ i = 0 n − 1 ( N n − 1 , i + f [ x 0 , x 1 , … , x n ] ω n , i ) x i + f [ x 0 , x 1 , … , x n ] ω n , n x n \sum_{i=0}^{n}N_{n,i}x^i=\sum_{i=0}^{n-1}(N_{n-1,i} + f[x_0,x_1,\ldots,x_n]\omega_{n,i})x^i+f[x_0,x_1,\ldots,x_n]\omega_{n,n}x^n i=0nNn,ixi=i=0n1(Nn1,i+f[x0,x1,,xn]ωn,i)xi+f[x0,x1,,xn]ωn,nxn

拆分之后得到

N n , i = { N n − 1 , i + f [ x 0 , x 1 , … , x n ] ω n , i , i < n f [ x 0 , x 1 , … , x n ] ω n , n , i = n N_{n,i}=\left\{ \begin{aligned} &N_{n-1,i} + f[x_0,x_1,\ldots,x_n]\omega_{n,i},& iNn,i={Nn1,i+f[x0,x1,,xn]ωn,i,f[x0,x1,,xn]ωn,n,i<ni=n

由于 ω n ( x ) = ( x − x 0 ) ( x − x 1 ) … ( x − x n − 1 ) = ω n − 1 ( x ) ∗ ( x − x n ) \omega_{n}(x)=(x-x_0)(x-x_1)\ldots(x-x_{n-1})=\omega_{n-1}(x)*(x-x_n) ωn(x)=(xx0)(xx1)(xxn1)=ωn1(x)(xxn),则

ω n , i = { ω n − 1 , 0 ∗ ( − x n ) i = 0 ω n − 1 , i ∗ ( − x n ) + ω n − 1 , i − 1 i ∈ [ 1 , n ] 1 i = n + 1 \omega_{n,i}=\left\{\begin{aligned} &\omega_{n-1,0}*(-x_{_n})&i=0\\ &\omega_{n-1,i}*(-x_{_n})+\omega_{n-1,i-1} & i\in[1,n]\\ &1&i=n+1 \end{aligned}\right. ωn,i= ωn1,0(xn)ωn1,i(xn)+ωn1,i11i=0i[1,n]i=n+1

polyMulti<-function(x){
    n = length(x)
    if(n<2) return(c(-x,1))
    omega = rep(0,n+1)
    omega[1] = - x[1]
    omega[2] = 1
    for(i in 2:n){
        omega[2:i] = -x[i]*omega[2:i]*+omega[1:(i-1)]
        omega[1] = -x[i]*omega[1]
        omega[i+1] = 1
    }
    return(omega)
}

Newton<-function(x,y){
    n = length(x)
    N = rep(0,n+1)
    N[1]=y[1]
    for(i in 1:n){
        omega = polyMulti(x[1:i])
        d = kDiffDiv(x[1:i],y[1:i],i-1)
        N[1:i] = N[1:i] + d*omega[1:i]
        N[i+1] = d*omega[i+1]
    }
    return(N)
}

验证一下

x = sort(rnorm(10))
y = x^5+2*x^4
N = Newton(x,y)
Y = y*0
for(i in 1:length(Y))
    for(j in 1:length(N))
        Y[i] = Y[i]+N[j]*x[i]^(j-1)
plot(x,y)
lines(x,Y)

R语言实现牛顿插值_第2张图片

可见效果还是不错的。

你可能感兴趣的:(R语言,R语言,牛顿插值,数学分析,数值分析,算法)