艾特肯(Aitken)逐步插值算法是代数插值中一个较为普遍的算法,对于拉格朗日插值,误差的余项并不能判断大小,而艾特肯插值法解决了余项的精度问题,该方法可以通过精度的要求逐步提高插值的阶,在插值过程中只需要通过两个低阶的插值结果进行线性拟合即可,并且计算方便。
具体实现过程就不多说了,我在代码里面注释的很清楚了!
代码如下:
//全区间艾特肯插值
//函数接口说明:
/* double Aitken(double* x,double *y ,int n,double t,double accu)
* x为输入数组指针,代表插值的横坐标集合
* y为输入数组指针,对应x中横坐标相对应的纵坐标的值
* n为插值结点的个数
* t为插值点的值
* accu是插值的精度要求
* 函数的返回值是double类型的,返回该插值结点对应的纵坐标
*/
#include<iostream>
#include<cmath>
using namespace std;
double Aitken(double* x, double* y, int n, double t, double accu)
{
int i, j, k; //循环变量
int m=10; //定义最大插值点的个数10
int l; //二分查找的中间变量
double xx[10], yy[10]; //存放线性插值的中间数组,由于最多10个点,所以大小为10
if (n < 1) throw("the number of point is less than 1"); //少于一个点,就抛出异常
if (n == 1) return y[0]; //一个点,直接返回该点的值
if (m > n) m = n; //判断点的个数,少于10个,就把插值点的值赋给m
//寻找最接近t的点
if (t <= x[0]) k = 1; //如果插值点t在结点最左边,插值区间下限为1
else if (t >= x[n - 1]) k = n; //在右边,插值区间上限为n
else
{
k = 1; j = n; //在中间,用二分查找那个点
while ((k - j != 1) && (k - j != -1))
{
l = (k + j) / 2;
if (t < x[l - 1])
j = l;
else
k = l;
}
if (fabs(t - x[l - 1]) > fabs(t - x[j - 1]))
k = j;
}
//从中心位置k寻找参加插值的结点
j = 1; l = 0;
for (i = 1; i <= m; i++) //该方法挑出中间点的元素,分别是k的左边一个、右边一个
{
k = k + j*l;
if ((k < 1) || (k > n)) //如果是左边或者右边没数了,就用这个挑出右边或左边的数
{
l = l + 1;
j = -j;
k = k + j*l;
}
xx[i - 1] = x[k - 1];
yy[i - 1] = y[k - 1];
l = l + 1;
j = -j;
}
//进行艾特肯逐步线性插值
/*该插值先计算xx[0],xx[1],得出结果放在yy[1]中
*接下来计算xx[0],xx[2],得出结果z,并继续计算yy[1]和z的值,存放在yy[2]中。
*依次类推
*yy[10]数组中存放的永远是插值的计算的对角线的元素(列出插值表可以看出)
*/
i = 0;
double z;
do
{
i = i + 1;
z = yy[i];
for (j = 0; j <= i - 1; j++)
z = yy[j] + (t - xx[j])*(yy[j] - z) / (xx[j] - xx[i]); //艾特肯逐步线性插值公式
yy[i] = z;
} while ((i != m - 1) && (fabs(yy[i] - yy[i - 1]) > accu));
return z;
}
int main()
{
double x[11] = { -1.0,-0.8,-0.65,-0.4,-0.3,0.0,0.2,0.4,0.6,0.8,1.0 };
double y[11] = { 0.0384615,0.0588236,0.0864865,0.2,0.307692,1.0,0.5,0.2,0.1,0.0588236,0.0384615 };
//double x[5] = { 0.3,0.4,0.5,0.6,0.7 };
//double y[5] = { 0.29850,0.39646,0.49311,0.58813,0.58122 };
double accu = 1.0e-8;
double t = -0.75;
double c;
c = Aitken(x, y, 11, t, accu);
cout << " " << c << endl;
t = 0.05;
c = Aitken(x, y, 11, t, accu);
cout << " " << c << endl;
return 0;
}