Newton(牛顿)插值法具有递推性,这决定其性能要好于Lagrange(拉格朗日)插值法。其重点在于差商(Divided Difference)表的求解。

步骤1. 求解差商表,这里采用非递归法(看着挺复杂挺乱,这里就要自己动笔推一推了,闲了补上其思路),这样,其返回的数组(指针)就是差商表了,

/*
* 根据插值节点及其函数值获得差商表
* 根据公式非递归地求解差商表
* x: 插值节点数组
* y: 插值节点处的函数值数组
* lenX: 插值节点的个数
* return: double类型数组
*/
double * getDividedDifferenceTable(double x[], double y[], int lenX) {
double *result = new double[lenX*(lenX - 1) / 2];
for (int i = 0; i < lenX - 1; i++) {
result[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i]);
}
int step = lenX - 1; // 增加步长
int yindex = lenX - 1; // 分子的基准值,线性减速递增
int xgap = 2; // 分母的间距,每次+1
int xstep = 2;
while (step >= 1) {
for (int i = 0; i < step - 1; i++) {
result[yindex + i] = (result[yindex - step + i + 1] - result[yindex - step + i]) / (x[xstep + i] - x[xstep + i - xgap]);
}
yindex += (step - 1);
xstep++;
step--;
xgap++;
} return result;
}

步骤 2. 取得差商表每一列的第一个作为基函数的系数

/**
* 从差商表中获取一定阶数的某个差商
* dd: 差商表
* len: 差商表的长度
* rank: 所取差商的阶数
* index: rank阶差商的第index个差商
* return: 返回double类型所求差商
*/
double getDividedDifference(double dd[], int len, int rank, int index) {
// 根据差商表的长度求解差商的最高阶数
// 由于差商表是三角形的,因此有规律可循,解方程即可
int rankNum = (int)(0.5 + sqrt(2 * len + 0.25) - 1);
printf("%d 阶差商 \n", rank);
int pos = 0;
int r = 1;
// 根据n+(n+1)+...+(n-rank)求得rank阶差商在差商表数组中的索引
while (rank > 1)
{
// printf("geting dd's index, waiting...\n");
pos += rankNum;
rank--;
rankNum--;
}
pos += index; // 然后加上偏移量,意为rank阶差商的第index个差商 return dd[pos];
}

步骤3. Newton 插值主流程

/*
* Newton Interpolating 牛顿插值主要代码
* x: 插值节点数组
* y: 插值节点处的函数值数组
* lenX: 插值节点个数(数组x的长度)
* newX: 待求节点的数组
* lennx: 待求节点的个数(数组lenX的长度)
*/
double *newtonInterpolation(double x[], double y[], int lenX, double newX[], int lennx) {
// 计算差商表
double *dividedDifferences = getDividedDifferenceTable(x, y, lenX);
//
double *result = new double[lennx]; // 求差商表长度
int ddlength = 0;
for (int i = 1; i < lenX; i++)
{
ddlength += i;
}
// 打印差商表信息
printf("=======================差商表的信息=======================\n");
printf("差商个数有:%d, 待插值节点个数:%d\n =======================差商表=======================", ddlength, lennx);
int ifnextrow = 0; // 控制打印换行
for (int i = 0; i < ddlength; i++) {
if (ifnextrow == (i)*(i + 1) / 2)
printf("\n");
printf("%lf, ", dividedDifferences[i]);
ifnextrow++;
}
printf("\n");
// 计算Newton Interpolating 插值
double ddi = 0;
double coef = 1;
for (int i = 0; i < lennx; i += 2) {
coef = (double)1;
result[i] = y[i];
printf("=============打印计算过程=============\n");
for (int j = 1; j < lenX -1; j++) {
coef *= (newX[i] - x[j - 1]);
ddi = getDividedDifference(dividedDifferences, ddlength, j, 0);
printf("取得差商: %lf\n", ddi);
result[i] = result[i] + coef * ddi;
printf("计算result[%d] + %lf * %lf", i, coef, ddi);
printf("获得结果result %d: %lf\n", i, result[i]);
}
printf("result[%d] = %lf\n", i, result[i]); // =======================选做题:求误差==========================
printf("求解截断误差 所需差商:%lf\n", getDividedDifference(dividedDifferences, ddlength, lenX-1, 0));
// printf("求解截断误差 所需多项式:%lf\n", coef);
printf("求解截断误差 所需多项式的最后一项:%lf - %lf\n", newX[i] , x[lenX - 2]);
result[i + 1] = getDividedDifference(dividedDifferences, ddlength, lenX - 1, 0)*coef*(newX[i] - x[lenX - 2]);
// ===============================================================
}
if (dividedDifferences) {
delete[] dividedDifferences;
}
return result;
}

步骤4. 主函数示例

int main()
{
std::cout << "Hello World!\n";
printf("Newton插值!\n");
double x[] = {0.40, 0.55, 0.65, 0.80, 0.90, 1.05};
//double x[] = { 1.5, 1.6, 1.7 };
int lenX = sizeof(x) / sizeof(x[0]);
double y[] = {0.41075, 0.57815, 0.69675, 0.88811, 1.02652, 1.25382};
//double y[] = { 0.99749, 0.99957, 0.99166 };
double newx[] = {0.596};
//double newx[] = { 1.609 };
// 计算牛顿插值结果和截断误差
double *result = newtonInterpolation(x, y, lenX, newx, 1);
printf("=====================最终结果=====================\n");
printf("求得sin(1.609)的近似值为:%lf\n", *result);
printf("截断误差:%.10lf\n", *(result + 1));
if (result) {
delete[] result;
}
return 0;
}

Newton插值的C++实现的更多相关文章

  1. 数值分析案例:Newton插值预测2019城市(Asian)温度、Crout求解城市等温性的因素系数

    数值分析案例:Newton插值预测2019城市(Asian)温度.Crout求解城市等温性的因素系数 文章目录 数值分析案例:Newton插值预测2019城市(Asian)温度.Crout求解城市等温 ...

  2. 等距结点下的Newton插值多项式系数计算(向前差分)

    插值多项式的牛顿法 1.为何需要牛顿法? ​ 使用Lagrange插值法不具备继承性.当求好经过\(({x_0},{y_0})-({x_n},{y_n})\)共n+1个点的插值曲线时候,如果再增加一个 ...

  3. Python实现Newton和lagrange插值

    一.介绍Newton和lagrange插值:给出一组数据进行Newton和lagrange插值,同时将结果用plot呈现出来1.首先是Lagrange插值:根据插值的方法,先对每次的结果求积,在对结果 ...

  4. 插值方法 - Newton向前向后等距插值

    通常我们在求插值节点的开头部分插值点附近函数值时,使用Newton前插公式:求插值节点的末尾部分插值点附近函数值时,使用Newton后插公式. 代码: 1 # -*- coding: utf-8 -* ...

  5. scipy插值与拟合

    原文链接:https://zhuanlan.zhihu.com/p/28149195 1.最小二乘拟合 实例1 import numpy as np import matplotlib.pyplot ...

  6. 拉格朗日插值和牛顿插值 matlab

    1. 已知函数在下列各点的值为   0.2 0.4 0.6 0.8 1.0   0.98 0.92 0.81 0.64 0.38 用插值法对数据进行拟合,要求给出Lagrange插值多项式和Newto ...

  7. 转Python SciPy库——拟合与插值

    1.最小二乘拟合 实例1 import numpy as np import matplotlib.pyplot as plt from scipy.optimize import leastsq p ...

  8. 多项式函数插值:全域多项式插值(一)单项式基插值、拉格朗日插值、牛顿插值 [MATLAB]

    全域多项式插值指的是在整个插值区域内形成一个多项式函数作为插值函数.关于多项式插值的基本知识,见“计算基本理论”. 在单项式基插值和牛顿插值形成的表达式中,求该表达式在某一点处的值使用的Horner嵌 ...

  9. 插值方法 - Newton多项式(非等距节点)

    不多话.Nowton插值多项式(非等距节点)代码: 1 # -*- coding: utf-8 -*- 2 """ 3 Created on Wed Mar 25 15: ...

随机推荐

  1. 【随笔】菜刀(代码执行)函数和命令执行函数详解及Getshell方法

    代码执行函数 VS 命令执行函数 一直想整理这两块的内容,但是一直没时间弄,直到前两天碰上一个写入了菜刀马但是死活连不上菜刀的站,顿时不知道怎么继续了,所以就趁这个机会整理了一下代码执行函数怎么get ...

  2. 独立看第一个C++程序到最终结果log----2019-04-16

    (如果一个人夸你,千万别相信,一个人真优秀是不需要说出来的,所以别人夸你的时候也是自己最松懈的时候,千万不能飘,只能说明自己不是很差而已,世界上优秀的人很多,一直优秀到最后的人却是凤毛菱角. 如果一个 ...

  3. shiro入门学习--授权(Authorization)|筑基初期

    写在前面 经过前面的学习,我们了解了shiro中的认证流程,并且学会了如何通过自定义Realm实现应用程序的用户认证.在这篇文章当中,我们将学习shiro中的授权流程. 授权概述 这里的授权指的是授予 ...

  4. 多测师讲解自动化测试 _RF连接数据库_高级讲师肖sir

    RF连接数据库:1.Connect To Database(连接数据库)2.Table Must Exist(表必须存在)3.Check If Exists In Database(查询某条件是否存在 ...

  5. Java 10 种常用第三方服务

    严格意义上说,所有软件的第三方服务都可以自己开发,不过从零到一是需要时间和金钱成本的.就像我们研发芯片,投入了巨大的成本,但仍然没有取得理想的成绩,有些事情并不是一朝一夕,投机取巧就能完成的. Jav ...

  6. zabbix安装中文语言包及中文乱码的解决(zabbix5.0)

    一,zabbix不能配置中文界面的问题: 1, zabbix5.0 系统安装后,web界面不能选择使用中文 系统提示: You are not able to choose some of the l ...

  7. centos8平台使用ip命令代替ifconfig管理网络

    一,为什么建议使用ip命令代替ifconfig? 1,ifconfig所属的net-tools包已经不再被维护了 虽然可以用,但会发生看不到部分ip等情况, [root@centos8 liuhong ...

  8. postgresql 导出数据库与数据表

    单表导出 pg_dump --host 127.0.0.1 --port 5432 --username "postgres" --role "postgres" ...

  9. BERT模型详解

    1 简介 BERT全称Bidirectional Enoceder Representations from Transformers,即双向的Transformers的Encoder.是谷歌于201 ...

  10. Docker知识总结

    目录 1 安装docker 2 docker基本概念 2.1 Docker是容器化平台 2.2 Docker体系结构 2.3 容器与镜像 3 docker常用命令 3.1 快速安装tomcat 3.1 ...