一、拉格朗日插值算法
(一)概念思想
1-介绍:在数值分析中,拉格朗日插值法是以法国十八世纪数学家约瑟夫·拉格朗日命名的一种多项式插值方法。许多实际问题中都用函数来表示某种内在联系或规律,而不少函数都只能通过实验和观测来了解。如对实践中的某个物理量进行观测,在若干个不同的地方得到相应的观测值,拉格朗日插值法可以找到一个多项式,其恰好在各个观测的点取到观测到的值。这样的多项式称为拉格朗日(插值)多项式。数学上来说,拉格朗日插值法可以给出一个恰好穿过二维平面上若干个已知点的多项式函数。
详细请参考:https://www.cnblogs.com/ECJTUACM-873284962/p/6833391.html
(二)例题
已知1920年-1970年美国人口如下
年份 | 1920 | 1930 | 1940 | 1950 | 1960 | 1970 |
人口(千人) | 105711 | 123203 | 131669 | 150697 | 179323 | 203212 |
- 构造5次Lagrange插值多项式,并用此估计1910年,1965年和2002年的人口数;
2. 用牛顿插值估计1965年和2012年的人口数。
(三)程序代码
#include<iostream>
using namespace std;
const int N = 1000;//预先定义插值节点的个数为1000个
//arrX[N],arrY[N]分别存放的是插值节点(Xi,Yi)即坐标,参数n为插值节点的个数,而参数x为待求解的插值节点的X值
//函数返回值为求解出来的插值节点X对应的Y值
float Lagrange(float arrX[], float arrY[], int n, float x);
int main()
{
float arrX[N], arrY[N];
int num;
cout << "输入插值节点的个数即你要构造几次插值函数(小于" << N << "个): ";
cin >> num;
cout << "\n--接下来输入这些插值节点(先输入X 再输入对应的Y)--\n";
for (int i = 0; i < num; i++)
{
cout << "第" << i + 1 << "个节点的X值: ";
cin >> arrX[i];
cout << "第" << i + 1 << "个节点的Y值: ";
cin >> arrY[i];
}
char ch='y';
while (ch='y')
{
float X;
cout << "\n--请输入你要估计哪一年的人口数--\n";
cin >> X;
float Res = Lagrange(arrX, arrY, num, X);
cout << "\n--第"<<X<<"年的人口数为: " << Res << "人"<<endl;
cout << "是否继续y/n:";
char ch;
cin >> ch;
if (ch != 'y')break;
}
return 0;
}
float Lagrange(float arrX[], float arrY[], int n, float x)
{
float yResult = 0.0;
float LValue[N];//LValue[N]存放的是每次求解的插值基函数的通项
float temp1, temp2;//插值基函数中的上下累乘temp1,temp2
for (int k = 0; k < n; k++)
{
temp1 = 1.0;
temp2 = 1.0;
for (int m = 0; m < n; m++)
{
if (m == k)//这里的设计是跳过正在使用的x,如正在使用x0,就跳过
{
continue;
}
temp1 *= (x - arrX[m]);
temp2 *= (arrX[k] - arrX[m]);
}
LValue[k] = temp1 / temp2;
}
for (int i = 0; i < n; i++)
{
yResult += arrY[i] * LValue[i];//构造插值函数
}
return yResult;
}
(四)运行结果
二、牛顿插值算法
(一)概念思想
1-牛顿插值公式(Newton interpolation formula)是代数插值方法的一种形式。牛顿插值引入了差商的概念,使其在插值节点增加时便于计算。
(二)例题 -->同上
(三)程序代码
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1000;//缺省设置最大坐标个数为1000
float Newton(float x[], float y[], int n, float X);//主算法声明,四个参数,x[]代表x坐标,y[]代表y坐标,n代表用户输入的坐标个数,X代表用户要估计的值
int main()
{
float X[N], Y[N];
int n;
cout << "输入插值节点的个数即你要构造几次插值函数(小于" << N << "个): ";
cin >> n;
cout << "\n--请输入插值节点--\n";
for (int i = 0; i < n; i++)
{
cout << "第" << i + 1 << "个节点的X值: ";
cin >> X[i];
cout << "第" << i + 1 << "个节点的Y值: ";
cin >> Y[i];
}
char ch = 'y';//设计一个循环使得用户可以多次估计想要的x值
while (ch = 'y')
{
float x;
cout << "\n 请输入你要估计哪一年的人口数: ";
cin >> x;
float Res = Newton(X, Y, n, x);
cout << "\n 第" << x << "年的人口数为: " << Res << "人" << endl;
cout << "是否继续y/n:";
char ch;
cin >> ch;
if (ch != 'y')break;
}
return 0;
}
float Newton(float x[], float y[], int n, float X)
{
float a[N];
a[0] = y[0];//a数组为每一个多项式
cout << " 输出差商表 " << "\n";
for (int i = 1; i <= n - 1; i++)
{
cout << i<<"阶差商:" << " ";
for (int j = 0; j < n - i; j++)
{
float temp1 = y[j];
float temp2 = y[j + 1];
y[j] = (temp2 - temp1) / (x[j + i] - x[j]);//差商核心算法
cout << y[j] << " ";
}
a[i] = y[0];//每个阶的第一个赋值放入a数组中
cout << "\n" << "\n";
}
float N = a[0];//特殊处理第一个,因为第一个只有y值,没有差商
for (int i = 0; i < n - 1; i++)
{
float sum2 = 1;//多项式
float temp = 1;
for (int j = 0; j <= i; j++)
{
temp *= (X - x[j]);//多项式的一部分
}
sum2 = a[i+1] * temp;//多项式的每一个子式
N = N + sum2;
}
return N;
}
(四)运行结果
——————每天八杯水