图形图像处理算法(3) ---- 多项式插值法

1. 多项式的定义

多项式(polynomial)是代数学的基本概念,简单的说是由称为未知数的变量和称为系数的常数通过有限次的加减法,乘法,以及自然数幂次的乘方运算得到的代数表达式。多项式是整式的一种。未知数只有一个的多项式称为一元多项式,下面就是一个一元二次多项式

下面所示是一个三元三次多项式:

一个多项式有几次取决于最高次幂的幂指数,有几元取决于未知数的个数,如果某一项不含未知数,称为常数项,多项式在数学的很多分支乃至自然科学中以及工程学中都有很重要的应用。

 2. 多项式插值法

有很多问题都可以按照函数的方式进行描述,然而这个函数通常是未知的,我们只能通过少量的已知的点来推断函数的大致模型,为了实现这个目的,在已知点之间做插值处理

多项式插值的根本点是建立一个特殊形式的多项式,称为插值多项式,多项式是具有如下形式的函数:

 这里的 a0..... an 是系数,当 an 是非零整数时,这种形式的多项式称为 n 阶多项式,这个是多项式的指数形式,在某些特定的环境中其他形式的多项式则更为简便,牛顿多项式的形式如下:

 这里的 a0..... an 是系数, c0..... cn 是中值,注意到   c0..... cn全为0时,牛顿插值多项式就退化为前面的定义的  n 阶多项,对于一个含有 n 个已知点的插值情景,就需要构建 n 次的的多项式,多项式的项数是 n + 1个

 3. 牛顿插值法

牛顿插值法的多项式定义是:

 其中的 x0...xn 是已知点的 x 坐标,f[x0...xn] 称为差商,差商的计算方法如下:

也就是说 f[xi...xj] 的差商要由 f[x(i+1)...xj] 和 f[xi...x(j-1)] 计算出来

 3.1 差商的计算

根据差商的定义,差商需要重复迭代的方法计算出来,下图是f[x0...x3] 的差商计算过程:

 3.2 C语言实现

牛顿插值法的C语言代码实现如下:

//  x 已知的点的x轴坐标   fx 已知的点y轴左边  n已知点的个数
//  z 插值点的x 轴坐标    pz 输出值 插值点的 y轴坐标  m 插值点的个数
static int interpol(const double *x, const double *fx, int n, double *z, double *pz, int m) {

	double term, *table, *coeff;
	int i, j, k;

	if ((table = (double*)malloc(sizeof(double)*n)) == NULL) {
		return -1;
	}

	if ((coeff = (double*)malloc(sizeof(double)*n)) == NULL) {
		free(table);
		return -1;
	}

	memcpy(table, fx, sizeof(double)*n);

	coeff[0] = table[0];


	//  计算差商的值
	for (k = 1; k < n; k++) {
        //  k = 1 计算第一阶差商的值
        //  k = 2 计算第二阶差商的值 table 被更新
        //  k = n-1  计算最后一阶差商的值,只有 table[0] 被更新
		for (i = 0; i < n - k; i++) {
			j = i + k;
			table[i] = (table[i + 1] - table[i]) / (x[j] - x[i]);
		}

		coeff[k] = table[0];
	}
	free(table);

	//  使用厂商构建插值多项式,以5阶多项式为例
	//  fx = coeff[0] (z-x0)(z-x1)(z-x2)(z-x3)(z-x4) +  coeff[1] (z-x0)(z-x1)(z-x2)(z-x3) + coeff[2](z-x0)(z-x1)(z-x2) +  coeff[3](z-x0)(z-x1) +  coeff[4](z-x0) + pz[0]

	for (k = 0; k < m; k++) {
		pz[k] = coeff[0];
		for (j = 1; j < n; j++) {
				term = coeff[j];
				for (i = 0; i < j; i++) {
					term = term*(z[k] - x[i]);
				}
				pz[k] = pz[k] + term;
		}
	}

	free(coeff);
	return 0;
}

#define INTERPOLSIZE 5

void testinterpol(int argc, char* argv[]) {
    
    //  以正弦为例,1000sinx 的插值
	double inputx[INTERPOLSIZE] = {0.0f, 45.0f, 90.0f, 135.0f, 180.0f};
	double fx[INTERPOLSIZE] = {0.0f, 707.0f, 1000.0f, 707.0f, 0.0f};

	double z[4] = {20.0f, 40.0f, 60.0f,80.0f};

	double pz[4] = { 0.0f };

	interpol(inputx, fx, INTERPOLSIZE, z, pz, 4);

	printf("output value: ");
	for (int i = 0; i < 4; i++) {
		printf("%f ", pz[i]);
	}
}

4. 牛顿插值法的验证

以 y=1000sinx 为例,插值得到的结果和实际验证的结果误差只有 1 左右:

已知{0,45,90,135,180} 通过插值得到 20,40,60,80的值

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值