用编程语言编程实现以下算法:
1.已知插值节点序列,用 拉格朗日 (Lagrange) 插值 多项式计算函数在点的近似值。
2.已知插值节点序列,用 牛顿 (Newton) 插值 多项式计算函数在点的近似值。
3.用 线性函数拟合 给定的数据。
语言:C++语言
导入扩展库:Eigen库
在项目名称处 右键->属性->VC++目录->包含目录->选择eigen模块所在文件夹路径,即可导入模块;
eigen资源文件可以在eigen官网上进行下载:http://eigen.tuxfamily.org/index.php?title=Main_Page
//拉格朗日插值法
//参数:插值点 points,计算点 x,插值点个数 n
double Lagrange(vector<Vector2d> points, double x, int n)
{
//运算结果
double result = 0;
//插值基函数
double L;
for (int k = 0; k < n; k++) {
//计算插值基函数
L = 1;
for (int j = 0; j < n; j++) {
//叠乘 (x-xj)/(xk-xj)
if (j != k) {
L = ((x - points[j][0]) / (points[k][0] - points[j][0]))*L;
}
}
//叠加 Lk * yk
result += L * points[k][1];
}
return result;
}
算法采用 计算差商表 的方法实现:
//牛顿插值法
double Newton(vector<Vector2d> points, double x, int n)
{
//运算结果
double result = 0;
//差商表
MatrixXd DQTable(n, n + 1);
DQTable.setZero();
//构造差商表 (i为行坐标 j为列坐标)
for (int i = 0; i < n; i++) {
//第0列为各插值点的x值
DQTable(i, 0) = points[i][0];
}
for (int i = 0; i < n; i++) {
//第1列为各插值点的y值
DQTable(i, 1) = points[i][1];
}
//计算各阶差商
for (int j = 2; j < n + 1; j++) {
for (int i = j - 1; i < n; i++) {
DQTable(i, j) = (DQTable(i, j - 1) - DQTable(i - 1, j - 1)) / (DQTable(i, 0) - DQTable(i - j + 1, 0));
}
}
// w = (x-x0)(x-x1)...(x-xn-1) 叠乘实现
double w = 1;
for (int k = 0; k < n; k++) {
if (k > 0) {
w = w * (x - points[k - 1][0]);
}
// 叠加 w * k阶差商 (差商表对角线)
result += w * DQTable(k, k + 1);
}
return result;
}
算法采用 法方程法 计算:
//一次多项式曲线拟合 y = a + b*x
//返回参数 a、b 组成的向量
Vector2d CurveFit(vector<Vector2d> points, int n)
{
double sum_x = 0; //x总和
double sum_x2 = 0; //x^2总和
double sum_y = 0; //y总和
double sum_xy = 0; //x * y总和
Matrix2d A; //2*2矩阵
Vector2d b; //向量
Vector2d x; //求解向量
for (int i = 0; i < n; i++) {
sum_x += points[i][0];
sum_x2 += pow(points[i][0], 2);
sum_y += points[i][1];
sum_xy += points[i][0] * points[i][1];
}
A(0, 0) = n;
A(1, 0) = A(0, 1) = sum_x;
A(1, 1) = sum_x2;
b(0) = sum_y;
b(1) = sum_xy;
//求解方程 Ax = b
x = A.lu().solve(b);
return x;
}
#include
#include
#include
#include
#include
using namespace Eigen;
using namespace std;
//拉格朗日插值法
//参数:插值点 points,计算点 x,插值点个数 n
double Lagrange(vector<Vector2d> points, double x, int n)
{
//运算结果
double result = 0;
//插值基函数
double L;
for (int k = 0; k < n; k++) {
//计算插值基函数
L = 1;
for (int j = 0; j < n; j++) {
//叠乘 (x-xj)/(xk-xj)
if (j != k) {
L = ((x - points[j][0]) / (points[k][0] - points[j][0]))*L;
}
}
//叠加 Lk * yk
result += L * points[k][1];
}
return result;
}
//牛顿插值法
double Newton(vector<Vector2d> points, double x, int n)
{
//运算结果
double result = 0;
//差商表
MatrixXd DQTable(n, n + 1);
DQTable.setZero();
//构造差商表 (i为行坐标 j为列坐标)
for (int i = 0; i < n; i++) {
//第0列为各插值点的x值
DQTable(i, 0) = points[i][0];
}
for (int i = 0; i < n; i++) {
//第1列为各插值点的y值
DQTable(i, 1) = points[i][1];
}
//计算各阶差商
for (int j = 2; j < n + 1; j++) {
for (int i = j - 1; i < n; i++) {
DQTable(i, j) = (DQTable(i, j - 1) - DQTable(i - 1, j - 1)) / (DQTable(i, 0) - DQTable(i - j + 1, 0));
}
}
// w = (x-x0)(x-x1)...(x-xn-1) 叠乘实现
double w = 1;
for (int k = 0; k < n; k++) {
if (k > 0) {
w = w * (x - points[k - 1][0]);
}
// 叠加 w * k阶差商 (差商表对角线)
result += w * DQTable(k, k + 1);
}
return result;
}
//一次多项式曲线拟合 y = a + b*x
//返回参数 a、b 组成的向量
Vector2d CurveFit(vector<Vector2d> points, int n)
{
double sum_x = 0; //x总和
double sum_x2 = 0; //x^2总和
double sum_y = 0; //y总和
double sum_xy = 0; //x * y总和
Matrix2d A; //2*2矩阵
Vector2d b; //向量
Vector2d x; //求解向量
for (int i = 0; i < n; i++) {
sum_x += points[i][0];
sum_x2 += pow(points[i][0], 2);
sum_y += points[i][1];
sum_xy += points[i][0] * points[i][1];
}
A(0, 0) = n;
A(1, 0) = A(0, 1) = sum_x;
A(1, 1) = sum_x2;
b(0) = sum_y;
b(1) = sum_xy;
//求解方程 Ax = b
x = A.lu().solve(b);
return x;
}
//读取点数据文件的函数
//参数:文件路径 path,计算点 x0
vector<Vector2d> ReadPointData(const string &path, double &x0)
{
//点集
vector<Vector2d> points;
//建立读入流对象
ifstream ifs(path);
if (!ifs.is_open()) return points;
//先读入计算点x坐标
ifs >> x0;
//循环读入点
double x, y;
while (!ifs.eof()) {
ifs >> x >> y;
points.push_back(Vector2d(x, y));
}
return points;
}
int main()
{
//插值点集
vector<Vector2d> points;
//曲线拟合参数 a、b
Vector2d v;
//运算点 x 坐标
double x;
//拉格朗日插值
points = ReadPointData("F://points1.txt", x);
cout << endl << "拉格朗日插值:" << "f(" << x << ") = " << Lagrange(points, x, points.size()) << endl;
//牛顿插值
points = ReadPointData("F://points2.txt", x);
cout << endl << "牛顿插值:" << "f(" << x << ") = " << Newton(points, x, points.size()) << endl;
//曲线拟合
points = ReadPointData("F://points3.txt", x); v = CurveFit(points, points.size());
cout << endl << "曲线拟合:" << "y = " << v[0] << " + " << v[1] << " * x" << endl;
return 0;
}
三个算法的实验数据分别存储在F盘的 三个txt文件 中,
通过 函数 ReadPointData 读取点数据。
points1.txt:(拉格朗日插值)
points2.txt:(牛顿插值)
points3.txt:(最小二乘线性拟合)
结果:
声明:本文内容来源于武汉理工大学2019-2020学年数值分析方法课程实验,仅供学习参考。
如有不足地方,还请指出。祝愿读者能够在编程之路上不断进步!