拉格朗日多项式插值及其c++演示

拉格朗日多项式插值及其c++演示,第1张

已知 n n n个点,寻找一条穿过所有点的曲线的过程叫做插值。如果这 n n n个点在某一条多项式的曲线上,那么,寻找这个多项式的解析式的过程就是多项式插值。
拉格朗日(Lagrange)插值是一种快速求解穿过 n n n个点的多项式的方法。这 n n n个点必须满足其横坐标两两不相同,否则不存在过这 n n n个点的多项式。而且,满足条件的 n − 1 n-1 n1次多项式只有一个。
最简单的例子就是两点确定一条直线,三个点确定一条抛物线。

拉格朗日系数多项式

假设 n n n个点 ( x 0 , y 0 ) , ( x 1 , y 1 ) , ⋯   , ( x n − 1 , y n − 1 ) (x_0,y_0),(x_1,y_1),\cdots,(x_{n-1},y_{n-1}) (x0,y0),(x1,y1),,(xn1,yn1),并且有 x 0 < x 1 < ⋯ < x n − 1 x_0x0<x1<<xn1.
定义函数 L k ( x ) = ( x − x 0 ) ( x − x 1 ) ⋯ ( x − x k − 1 ) ( x − x k + 1 ) ⋯ ( x − x n − 1 ) ( x k − x 0 ) ( x k − x 1 ) ⋯ ( x k − x k − 1 ) ( x k − x k + 1 ) ⋯ ( x k − x n − 1 ) L_k(x)=\frac{(x-x_0)(x-x_1)\cdots(x-x_{k-1})(x-x_{k+1})\cdots(x-x_{n-1})}{(x_k-x_0)(x_k-x_1)\cdots(x_k-x_{k-1})(x_k-x_{k+1})\cdots(x_k-x_{n-1})} Lk(x)=(xkx0)(xkx1)(xkxk1)(xkxk+1)(xkxn1)(xx0)(xx1)(xxk1)(xxk+1)(xxn1).
很显然 L k ( x ) L_k(x) Lk(x)具有下面的性质:
L k ( x i ) = { 1 , i = k 0 , i ≠ k \begin{aligned} L_k(x_i)=\left \{ \begin{aligned} 1,i=k\ 0,i\neq k \end{aligned} \right. \end{aligned} Lk(xi)={1,i=k0,i=k
而且 L k ( x ) L_k(x) Lk(x)只跟横坐标有关,与纵坐标无关,有时也叫做拉格朗日基函数。
根据拉格朗日系数多项式,可以快速求出过点 ( x 0 , y 0 ) , ( x 1 , y 1 ) , ⋯   , ( x n − 1 , y n − 1 ) (x_0,y_0),(x_1,y_1),\cdots,(x_{n-1},y_{n-1}) (x0,y0),(x1,y1),,(xn1,yn1)的多项式 p ( x ) p(x) p(x).
p ( x ) = y 0 L 0 ( x ) + y 1 L 1 ( x ) + ⋯ + y n − 1 L n − 1 ( x ) . p(x)=y_0L_0(x)+y_1L_1(x)+\cdots+y_{n-1}L_{n-1}(x). p(x)=y0L0(x)+y1L1(x)++yn1Ln1(x).
根据 L k ( x ) L_k(x) Lk(x)的性质, p ( x ) p(x) p(x)显然过点 ( x 0 , y 0 ) , ( x 1 , y 1 ) , ⋯   , ( x n − 1 , y n − 1 ) (x_0,y_0),(x_1,y_1),\cdots,(x_{n-1},y_{n-1}) (x0,y0),(x1,y1),,(xn1,yn1)

c++演示代码

代码中使用系数表示法表示一个多项式,数组下标表示次数,对应的值是该次数的系数。如 1 + 2 x + 3 x 2 + 4 x 3 1+2x+3x^2+4x^3 1+2x+3x2+4x3表示为 [ 1 , 2 , 3 , 4 ] [1,2,3,4] [1,2,3,4].

#include
#include
using namespace std;
class Lagrange{
	vector<vector<double>> points;// a point is (x,y)
	public:
		void setPoints(vector<vector<double>> points){
			this->points=points;
		}
		vector<double> interpolate(){
			vector<vector<double>> ls(points.size());
			for(int i=0;i<ls.size();i++){
				ls[i]=Lk(i);
				cout<<"The L"<<i<<"(x) is "<<endl; 
				for(auto it:ls[i]){
					cout<<it<<' ';
				}
				cout<<endl;
			}
			vector<double> res(points.size(),0);
			for(int i=0;i<ls.size();i++){
				for(int j=0;j<res.size();j++){
					res[j]+=points[i][1]*ls[i][j];
				}
			}
			return res;
		}
		vector<double> Lk(int k){
			double denominator=1;
			for(int i=0;i<points.size();i++){
				if(i==k){
					continue;
				}
				denominator*=points[k][0]-points[i][0];
			}
			vector<double> res(points.size(),0);
			Lk_help(k,0,0,1,res);
			for(int i=0;i<res.size();i++){
				res[i]=res[i]/denominator;
			}
			return res;
		}
		void Lk_help(int k,int i,int exp,double val,vector<double>& l){
			if(i>=points.size()){
				l[exp]+=val;
				return;
			}
			if(i==k){
				Lk_help(k,i+1,exp,val,l);
				return;	
			}
			Lk_help(k,i+1,exp,-val*points[i][0],l);
			Lk_help(k,i+1,exp+1,val,l);
		}
};
int main(){
	Lagrange ll;
	vector<vector<double>> p={{0,1},{1.2,0.362358},{2.6,34},{3.2,7.8}};
	ll.setPoints(p);
	vector<double> res=ll.interpolate();
	cout<<"The result is"<<endl;
	for(auto i:res){
		cout<<i<<' ';
	}
	cout<<endl<<endl;;
	for(int i=0;i<p.size();i++){
		double y=0;
		for(int k=res.size()-1;k>=0;k--){
			y=y*p[i][0]+res[k];
		}
		cout<<"The original y is "<<p[i][1]<<", computed y is "<<y<<endl;
	}
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/716972.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存