文章目录
- 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]=x1−x0f(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]=x2−x1f[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]=xk−xk−1f[x0,x1,…,xk−2,xk]−f[x0,x1,…,xk−1]
若将 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 xi−xj的乘积,可以表示为
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=0∑k(xj−x0)…(xj−xj−1)(xj−xj+1)…(xj−xk)f(xj)
其中第 j j j项的分母中不存在 x j − x j x_j-x_j xj−xj。则
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,…,xk−1]f[x1,…,xk]=j=0∑k−1(xj−x0)…(xj−xj−1)(xj−xj+1)…(xj−xk−1)f(xj)=j=1∑k(xj−x1)…(xj−xj−1)(xj−xj+1)…(xj−xk)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]=xk−x0f[x1,x2,…,xk]−f[x0,x1,…,xk−1]
根据这个表达式,可以通过一个简单的递归程序计算数组的差商
# 差商算法,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")
如图所示
牛顿插值
可见差商与微分在阶数上有着一致的趋势。那么,知道了差商之后,可以做点什么呢?
根据差商定义,可得
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,…,xn−1]=f(x0)+f[x,x0](x−x0)=f[x0,x1]+f[x,x0,x1](x−x1)⋮=f[x0,x1,…,xn]+f[x,x0,x1,…,xn](x−xn)
可见,通过差商可以逼近函数的真实值,将上式合并可得
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](x−x0)+f[x0,x1,x2](x−x0)(x−x1)+…+f[x0,x1,…,xn](x−x0)(x−x1)…(x−xn−1)+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](x−x0)+f[x0,x1,x2](x−x0)(x−x1)+…+f[x0,x1,…,xn](x−x0)(x−x1)…(x−xn−1)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)=(x−x0)(x−x1)…(x−xn), 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=0∑nNn,ixi=i=0∑n−1Nn−1,ixi+f[x0,x1,…,xn]i=0∑nω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=0∑nNn,ixi=i=0∑n−1(Nn−1,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},& i<n\\ &f[x_0,x_1,\ldots,x_n]\omega_{n,n},\quad &i=n \end{aligned}\right. Nn,i={Nn−1,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)=(x−x0)(x−x1)…(x−xn−1)=ωn−1(x)∗(x−xn),则
ω 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=⎩ ⎨ ⎧ωn−1,0∗(−xn)ωn−1,i∗(−xn)+ωn−1,i−11i=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)
可见效果还是不错的。