插值可能是用到最多和最简单的一种数据处理方法了,最近学了一些插值方面的内容,因此做了一些插值的练习,设计了一个小实验。
1. 实验要求
1).算法需要的是针对同一组数据,采用拉格朗日法,牛顿插值法,分段线性插值法来进行比较不同算法下同一数据的精度情况或误差情况;
2).针对三个算法的任意某一种算法,请分别考虑同一组数据进行插值时选择不同的节点数来进行计算的误差情况或精度情况;
3).针对三个算法的任意某一种算法,请分别考虑同一组数据进行插值时选择不同的步长来进行计算时的精度或误差。
2. 设计实现
针对实验的要求,设计了一个Interpolation类来实现插值计算,包含三个函数getLagrangeResult,getNewtonResult,getPiecewiseLinearResult分别代表拉格朗日插值,牛顿插值,分段线性插值。
拉格朗日插值
拉格朗日插值公式原理如下所示:
根据拉格朗日插值公式给出了C++的代码如下:
void Interpolation::getLagrangeResult(vector<float> &X,vector<float>&resY)
{
//检查X,Y是否相等
if(xdata.size()!= ydata.size())
return;
intdLength = xdata.size();
int xLength= X.size();
resY.resize(xLength);
for(int k = 0;k < xLength;k++)
{
floattemp = 0;
for(int i = 0;i <dLength;i++ )
{
temp = ydata[i];
for(int j = 0;j<dLength;j++ )
{
float inc = xdata[i]-xdata[j];
if(i!=j && inc != 0)
temp*= (X[k] - xdata[j])/inc;
}
resY[k] += temp;
}
}
}
牛顿插值
牛顿插值的公式如下图所示
根据牛顿插值公式给出了C++的代码如下:
void Interpolation::getNewtonResult(vector<float> &X,vector<float>&resY)
{
//检查X,Y是否相等
if(xdata.size()!= ydata.size())
return;
//计算差商表
intdLength = xdata.size();
intxLength = X.size();
resY.resize(xLength);
float*df = new float[dLength];
//初始化差商
for(int i = 0;i < dLength;i++)
df[i] = ydata[i];
//计算差商
for(int i = 0;i < dLength-1;i++)
{
floatprev = df[i];
for(int j = i+1;j < dLength;j++)
{
float temp;
temp = df[j];
df[j]=(prev-df[j])/(xdata[j-i-1]-xdata[j]);
prev = temp;
}
}
//计算插值
for(int i = 0;i <xLength;i++)
{
for(int j = 0;j < dLength-1;j++)
{
float temp = df[j];
for(int k = 0;k <j;k++)
temp *= X[i]-xdata[k];
resY[i] += temp;
}
}
delete[]df;
}
分段线性插值
分段线性插值,也就是线性的样条插值,即将各个插值数据点用直线连接起来,公式如下所示:
根据分段线性插值公式给出了C++的代码如下:
voidInterpolation::getPiecewiseLinearResult(vector<float>&X,vector<float> &resY)
{
intdLength = xdata.size();
intxLength = X.size();
resY.resize(xLength);
int idx= 0;
floatdata = xdata[0];
//计算最小值
for(int i = 0;i < xLength;i++ )
{
for(int j = 0;j < dLength;j++)
{
//minMax
if(xdata[j] < X[i])
{
data =xdata[j];
idx = j;
}
}
//插值
intidx1 =(idx == xdata.size()-1) ? xdata.size()-2 : idx;
intidx2 = idx1+1;
resY[i] =
(X[i]-xdata[idx2])*ydata[idx1]/(xdata[idx1]-xdata[idx2])
+(X[i]-xdata[idx1])*ydata[idx2]/(xdata[idx2]-xdata[idx1]);
}
}
3. 误差分析
对各个插值进行实验分析,使用Qt开发了一个插值分析器,以Sin(x)为目标函数,分别对各种情况下插值进行分析。
实验一:
在区间[0,6.28]之间,以采样间隔为1对插值目标函数进行采样,分别采用拉格朗日插值法,牛顿插值法,分段线性插值法使用其步长0.2对其进行插值,插值曲线图如下所示:
三种插值的误差表如下所示:
分段线性插值 | 牛顿插值 | 拉格朗日插值 | |
0.2 | 0.030375 | 0.011643 | 0.013884 |
0.4 | 0.05283 | 0.012888 | 0.015407 |
0.6 | 0.05976 | 0.009239 | 0.011076 |
0.8 | 0.044179 | 0.00426 | 0.005125 |
1 | 0 | 0 | 0 |
1.2 | 0.077003 | 0.002628 | 0.003188 |
1.4 | 0.116848 | 0.003495 | 0.004262 |
1.6 | 0.117407 | 0.002952 | 0.00362 |
1.8 | 0.078116 | 0.001581 | 0.001952 |
2 | 1.19E-07 | 0 | 0 |
2.2 | 0.052835 | 0.001276 | 0.001601 |
2.4 | 0.073437 | 0.00192 | 0.002431 |
2.6 | 0.06711 | 0.001826 | 0.002337 |
2.8 | 0.040233 | 0.001097 | 0.001421 |
3 | 2.98E-08 | 0 | 2.24E-07 |
3.2 | 0.01991 | 0.001105 | 0.001475 |
3.4 | 0.037492 | 0.001853 | 0.002521 |
3.6 | 0.044887 | 0.001964 | 0.00273 |
3.8 | 0.03464 | 0.001315 | 0.001875 |
4 | 1.79E-07 | 5.96E-08 | 2.38E-07 |
4.2 | 0.074349 | 0.001653 | 0.002518 |
4.4 | 0.113951 | 0.00311 | 0.004948 |
4.6 | 0.115615 | 0.003711 | 0.00623 |
4.8 | 0.077665 | 0.002812 | 0.005053 |
5 | 2.38E-07 | 0 | 1.79E-07 |
5.2 | 0.060432 | 0.004628 | 0.010248 |
5.4 | 0.085644 | 0.010115 | 0.026654 |
5.6 | 0.080048 | 0.014223 | 0.049481 |
5.8 | 0.049285 | 0.012952 | 0.077924 |
6 | 3.87E-07 | 1.19E-07 | 0.109671 |
6.2 | 0.060424 | 0.033817 | 0.140428 |
由实验结果可得,在本实验条件下,线性插值误差较大,牛顿插值和拉格朗日插值表现较为相近。
实验二:
在区间[0,6.28]之间,以采样间隔为0.25,0.5,1对插值目标函数进行采样,采用分段线性插值法对其使用其步长0.2对其进行插值实验,插值曲线和误差表如下所示:
三种采样间隔如下表所示:
采样间隔1 | 采样间隔0.5 | 采样间隔0.25 | |
0.2 | 0.030375 | 0.006899 | 0.000746 |
0.4 | 0.05283 | 0.005878 | 0.002801 |
0.6 | 0.05976 | 0.012808 | 0.004332 |
0.8 | 0.044179 | 0.020703 | 0.003751 |
1 | 0 | 0 | 0 |
1.2 | 0.077003 | 0.028159 | 0.004557 |
1.4 | 0.116848 | 0.01916 | 0.007359 |
1.6 | 0.117407 | 0.019718 | 0.007482 |
1.8 | 0.078116 | 0.029271 | 0.004799 |
2 | 1.19E-07 | 5.96E-08 | 5.96E-08 |
2.2 | 0.052835 | 0.023529 | 0.004178 |
2.4 | 0.073437 | 0.014826 | 0.005151 |
2.6 | 0.06711 | 0.0085 | 0.003754 |
2.8 | 0.040233 | 0.010927 | 0.001435 |
3 | 2.98E-08 | 0 | 1.49E-08 |
3.2 | 0.01991 | 0.002733 | 4.20E-05 |
3.4 | 0.037492 | 0.003139 | 0.001793 |
3.6 | 0.044887 | 0.010533 | 0.003426 |
3.8 | 0.03464 | 0.017463 | 0.003248 |
4 | 1.79E-07 | 5.96E-08 | 5.96E-08 |
4.2 | 0.074349 | 0.026482 | 0.004224 |
4.4 | 0.113951 | 0.018217 | 0.007088 |
4.6 | 0.115615 | 0.019882 | 0.007456 |
4.8 | 0.077665 | 0.029798 | 0.004945 |
5 | 2.38E-07 | 1.19E-07 | 5.96E-08 |
5.2 | 0.060432 | 0.025884 | 0.004522 |
5.4 | 0.085644 | 0.016548 | 0.005867 |
5.6 | 0.080048 | 0.010951 | 0.004631 |
5.8 | 0.049285 | 0.014737 | 0.002096 |
6 | 3.87E-07 | 1.49E-07 | 5.96E-08 |
6.2 | 0.060424 | 0.025876 | 0.000663 |
由实验结果可得,随着插值节点的密集,误差明显变小。
实验三:
在区间[0,6.28]之间,以采样间隔为1对插值目标函数进行采样,采用分段线性插值法使用其步长0.2,0.5,0.8对其进行插值实验,插值曲线和误差表如下所示:
三种不同步长的误差如下图所示:
步长0.2 | 步长0.5 | 步长0.8 | |||
0.2 | 0.030375 | 0.5 | 0.05869 | 0.8 | 0.044179 |
0.4 | 0.05283 | 1 | 0 | 1.6 | 0.117407 |
0.6 | 0.05976 | 1.5 | 0.122111 | 2.4 | 0.073437 |
0.8 | 0.044179 | 2 | 0 | 3.2 | 0.01991 |
1 | 0 | 2.5 | 0.073263 | 4 | 0 |
1.2 | 0.077003 | 3 | 0 | 4.8 | 0.077665 |
1.4 | 0.116848 | 3.5 | 0.042942 | 5.6 | 0.080048 |
1.6 | 0.117407 | 4 | 0 | ||
1.8 | 0.078116 | 4.5 | 0.119667 | ||
2 | 1.19E-07 | 5 | 0 | ||
2.2 | 0.052835 | 5.5 | 0.08637 | ||
2.4 | 0.073437 | 6 | 0 | ||
2.6 | 0.06711 | ||||
2.8 | 0.040233 | ||||
3 | 2.98E-08 | ||||
3.2 | 0.01991 | ||||
3.4 | 0.037492 | ||||
3.6 | 0.044887 | ||||
3.8 | 0.03464 | ||||
4 | 1.79E-07 | ||||
4.2 | 0.074349 | ||||
4.4 | 0.113951 | ||||
4.6 | 0.115615 | ||||
4.8 | 0.077665 | ||||
5 | 2.38E-07 | ||||
5.2 | 0.060432 | ||||
5.4 | 0.085644 | ||||
5.6 | 0.080048 | ||||
5.8 | 0.049285 | ||||
6 | 3.87E-07 | ||||
6.2 | 0.060424 |
由实验结果可得,步长越小,得到的插值结果越精确。