Lagrange插值法
考虑有$n$个不同的点 , 定义函数满足在满足克罗内克符号函数 ,
此时,若另
则对于任意$x_i$有
即$n$个点必然经过$L(x)$,即为所求。
再考虑$l_i(x)$,其应为一个$n-1$次多项式,则可由因式法写出满足要求的函数:
这里的$l_i(x)$称为插值基函数。
以下是代码实现
#include<stdio.h>
#include<stdlib.h>
float x[7] = {1.20, 1.24, 1.28, 1.32, 1.36, 1.40};
float y1[7] = {1.09545, 1.11355, 1.13137,1.14891, 1.16619, 1.18322};
float y2[7] = {0.07918, 0.09342, 0.10721, 0.12057, 0.13354, 0.14613};
float xi[6] = {1.22, 1.26, 1.30, 1.34, 1.38};
float Lagrange(float *y,float cx)
{
int n=6;
float temp[10],ans=0;
for(int i=0;i<n;i++)
{
temp[i] = y[i];
for(int j=0;j<n;j++)
if(j!=i)
temp[i] *= (cx - x[j]) / (x[i] - x[j]);
ans += temp[i];
}
return ans;
}
int main()
{
for (int i = 0; i < 5;i++)
printf("当x=%.2f,y1=%.5f,y2=%.5f\n", xi[i], Lagrange(y1,xi[i]),Lagrange(y2,xi[i]));
system("pause");
return 0;
}
我们可以发现假如新加入一个点,就必须得重新计算,这是它的缺点.
Newton插值法
该方法确定了一组新的基函数,确保能加入新的点能够重用之前的计算结果:
可以看到由于,因此可以重用之前的结果。
则最终的多项式为:
现在仅仅需要确定$a_i$的值就可以确定$N(x)$。
我们将每个点依次带入相减可得到一个神奇的规律:
我们把这种叫做差商,0阶均差定义为$f[x_i]=f(x_i)$,$n-1$阶差商为:
下面是差商表,每次迭代也可重用上一步的结果
所以最终为
以下是代码,可想而知,虽然Newton插值效率提高了,但是也要多出一部分来计算差商
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
float x[7] = {1.20, 1.24, 1.28, 1.32, 1.36, 1.40};
float y1[7] = {1.09545, 1.11355, 1.13137,1.14891, 1.16619, 1.18322};
float y2[7] = {0.07918, 0.09342, 0.10721, 0.12057, 0.13354, 0.14613};
float xi[6] = {1.22, 1.26, 1.30, 1.34, 1.38};
float diff[10][10];//差商值表
float phi[10];//基函数值
int n=6;
//求差商表,有点像动态规划
void DifferenceQuotient(float *y)
{
for (int i = 0; i < n;i++)
diff[i][0] = y[i];
for (int i = 1; i < n;i++)
{
for (int j = 1 ; j < i+1;j++)
diff[i][j] = (diff[i][j - 1] - diff[i-1][j - 1]) / (x[i] - x[i-j]);
}
}
float Newton(float *y,float cx)
{
phi[0] = 1;
float ans = 0;
for (int i = 1; i < n;i++) //其基函数的值
phi[i] = phi[i-1]*(cx - x[i-1]);
for (int i = 0; i < n;i++)
ans += phi[i] * diff[i][i];//多项式求和为最终结果
return ans;
}
int main(){
DifferenceQuotient(y1);
for (int i = 0; i < 5;i++)
printf("当x=%.2f,y1=%.5f\n", xi[i], Newton(y1,xi[i]));
cout << endl;
DifferenceQuotient(y2);
for (int i = 0; i < 5;i++)
printf("当x=%.2f,y2=%.5f\n", xi[i],Newton(y2,xi[i]));
system("pause");
}
如果要新增节点,可以增量更新差商表
两者关系
其实我们可以发现两个方法都是通过$n$个点确定了一组$n$个方程的方程组:
矩阵形式为$Y=XA$
系数矩阵$X$为范德蒙行列式,则$|X|\not =0$,因此可以得出其解$A$唯一,故最终确定的多项式唯一,即两者等效.Largrane法较为简单,而Newton法在需要新增节点时可以保持很好的效率。
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!