数值计算算法-多项式插值算法的实现与分析

数值计算是指在数值分析领域中的算法。数值分析是专门研究和数字以及近似值相关的数据问题,数值计算在数值分析的研究中发挥了特别重要的作用。

多项式插值是计算函数近似值的一种方法。其中函数值仅在几个点上已知。

该算法的基础是建立级数小于等于n的一个插值多项式pn(z),其中n+1是已知函数值的点的个数。

多项式插值法

许多问题都可以按照函数的方式来描述。然而,通常这个函数是未知的,我们只能通过少量的已知点来推断函数的大致模型。为了实现这个目的,在已知点之间做插值处理。如图所示,关于函数f(x),已知的点为x0...x8,在图中以黑色的圆点表示。通过插值法的帮助,我们能够获取函数在z0、z1、z2处的值,在图中以白色小方块表示。本节主要讨论多项式插值法。

多项式插值法的根本点就是要建立一个特殊形式的多项式,称为插值多项式

为了深入理解插值多项式的意义,我们先来看看多项式的一些基本法则:

首先,多项式是具有如下形式的函数:

p(x) = a0 + a1x + a2x2 + ... + anxn

这里的a0,...,an是系数当an为非零整数时,这种形式的多项式称为n阶多项式。这是多项式的指数形式,在数学问题中尤为常见。但是,在某些特定的环境中其他形式的多项式则更为简便。比如,在有关多项式插值问题中,牛顿插值多项式就是一个很好的例子

p(x) = a0 + a1 (x - c1) + a2 (x - c1)(x - c2) + ... + an(x - c1)(x - c2)...(x - cn)

这里a0,...,an系数,而c0,...,cn中值。注意到,当c0,...,cn全为0时,牛顿插值多项式就退化为前面定义的n阶多项式。

构建插值多项式

下面我们来看看如何对函数f(x)构建一个插值多项式。

为了对函数f(x)进行插值,要构建一个阶数小于等于n的多项式pn(z),而这又需要用到函数f(x)的n+1个已知点:x0,...,xn这些已知点x0,...,xn就称为插值点。通过插值多项式pn(z)可以计算出函数f(x)在x=z处的近似值。插值法需要满足点z在[x0,xn]内。可以采用如下公式来构建插值多项式pn(z)。

pn(z) = f[x0] + f[x0,x1](z-x0) + f[x0,x1,x2](z-x0)(z-x1) + ... + f[x0,...,xn](z-x0)(z-x1)...(z-xn-1)

其中函数f(x)在点x0,...,xn处的值已知,而f[x0],...,f[x0,...,xn]则称为差商

差商可以通过点x0,...,xn以及函数f(x)在这些点处的值来计算得出。这就是牛顿插值多项式的计算公式。注意到该公式同牛顿插值多项式的相同点。差商的计算公式为:

f[xi,...,xj] = f(xi)                                               如果i=j

f[xi,...,xj] = ( f[xi+1,...xj] - f[xi,...xj-1] ) / (xj - xi) 如果i < j

 通过这个公式不难看出,当i < j时,必须预先计算出其他的差商值。例如,要计算f[x0,x1,x2,x3],就需要先计算出f[x1,x2,x3]和f[x0,x1,x2]的值。幸运的是,可以通过一个差商表来帮助我们以一种系统的方式来计算差商值。如下图。

差商表由多行组成。最顶行保存已知点x0,...,xn 的值。第二行保存f[x0],...,f[xn]的值。要计算出表中其他的差商值,从每个待求的差商值处画一条对角线,使其回到f[xi]和f[xj](如下图中差商f[x1,x2,x3]处的虚线)要得到分母中的xi和xj,直接通过xi和xj求得。分子中的两个差商就是前一阶段计算出来的结果

当完成了整个差商表的计算后,插值多项式的系数就是从第二行开始,每行最左边的那一项

计算插值多项式

一旦确定了插值多项式的系数,对于函数f,如果我们想知道某个点处的函数值,只需要对多项式求值即可

比如,已知函数f在4个点处的函数值:x0=-3.0,f(x0)=-5.0;x1=-2.0,f(x1)=-1.1;x2=2.0,f(x2)=1.9;x3=3.0,f(x3)=4.8;现在要求出点z0=-2.5,z1=0.0,z2=1.0,z3=2.5处的函数值。由于已经知道函数f在4个点处的值,因此插值多项式为3阶。下图是3阶插值多项式p3(z)的差商表。

一旦从差商表中得到了系数,就可以采用前面介绍过的牛顿公式来构建插值多项式p3(z)

p3(z)=-5.0 + 3.9(z+3.0) + (-0.63)(z+3.0)(z+2.0) + 0.1767(z+3.0)(z+2.0)(z-2.0)

下一步可以通过该多项式计算出每个点z处的函数值。比如,在点z=-2.5处,经过如下计算得到

p3(z)=-5.0 + 3.9(-2.5+3.0) + (-0.63)(-2.5+3.0)(-2.5+2.0) + 0.1767(-2.5+3.0)(-2.5+2.0)(-2.5-2.0) = -2.694

点z1、z2、z3处的函数值可以通过相似的方法计算得出。最终结果以表格和函数图像的方式表达。如下图。

和任何其他近似算法一样,通常会有一些与插值多项式相关的误差出现,理解这一点很重要。定性的来讲,如果要使误差降至最小,构建的插值多项式必须要在函数f(x)上获取足够多的已知点才行。并且点与点之前的距离要适当,这样最终得到的多项式才能精确地表示出函数的特性。

多项式插值的接口定义

interpol


int interpol ( const double *x, const double *fx, int n, double *z, double *pz, int m );

返回值:如果插值操作成功,返回0;否则返回-1;

描述:采用多项式插值法来求得函数在某些特定点上的值。

由调用者在参数x处指定函数值已知的点集。每个已知点所对应的函数值都在fx中指定。对应待求的点由参数z来指定,而z所对应的函数值将在pz中返回x和f(x)中的元素个数由参数n来表示。z中的待求点的个数(以及pz中返回值个数)由参数m来表示。由调用者管理x、fx、z以及pz所关联的存储空间。

复杂度:O(mn2),这里m代表待求值的个数,而n代表已知点的个数。

多项式插值的实现与分析

多项式插值法主要基于对一系列期望点的插值多项式的确定。要得到这个多项式,首先必须通过计算差商来确定该多项式的系数。

首先,为差商以及待确定的系数分配存储空间。注意,由于差商表中每一行的每一项都仅依赖于其前一行的计算结果,因此,并不需要一次性保留所有的表项。所以,只为最占用空间的行分配空间即可该行将有n个条目

接下来,用fx中的值来初始化差商表的第一行。这是为计算差商表中的第三行做准备。(前两行不需要计算,因为这两行中的条目都已经保存在x和fx中)。

初始化的最后一步是在coeff[0]中保存fx[0]的值,因为这是插值多项式的第一个系数

计算差商的过程涉及一个嵌套循环,我们在循环中根据前面介绍过的公式来计算差商。在外层循环中,k用来统计正在计算的是哪一行(排除x和fx所代表的行)。在内层循环中i表示在当前行中正在计算的是哪一个条目一旦计算完一行的条目,table[0]中的值就成为插值多项式的下一个系数。因此,保存该值到coeff[k]中一旦得到插值多项式的所有系数,就可以计算出z中每个目标点的值,最后将这些值保存在pz中。

 我们命名这个函数为interpol,它的时间复杂度为O(mn2这里m代表z中的元素个数(也是pz中值的个数),n代表x中(也是fx中)的元素个数。复杂度因子n2是这样得到的,变更j控制循环中的每次迭代,当前迭代中需要乘以的因子比上一轮要多一个。也就是说,当j=1时,term需要做1次乘法,当j=2时,term需要做2次乘法,持续这个过程直到j=n-1时,term需要做n-1次乘法。实际上,这就成了对1~n-1的整数求和,得到的计算时间为T(n)=(n(n+1)/2)-n,再乘以某段固定的时间。(这是由计算等差数列的著名公式得到的)。在大O记法中可以简化为O(n2)。O(mn2)中的因子m来源于针对z中的每个点计算多项式插值的过程。在第一个嵌套循环中,计算出所有的差商,其复杂度为O(n2)。因此,最终的复杂度有一个额外的因子m,该因子对实际的复杂度没有多大的影响。

示例:多项式插值的实现

/*interpol.c*/
#include <stdlib.h>
#include <string.h>#include "nummeths.h"/*interpol  */
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用来统计正在计算的是哪一行*/{for(i=0; i<n-k; i++)/*内层循环i表示在当前行中正在计算的是哪一个条目(随之行数的增加,条目减少)*/{j=i+k;/*当前行的每一项中分子的差商就是其前一阶段计算的结果*/table[i] = (table[i+1] - table[i]) / (x[j] - x[i]);}/*当前行的首个条目计算结果即是多项式的下一个系数*/coeff[k]=table[0];}free(table);/*在指定点上对插值多项式进行求值(循环构造插值多项式)*/for(k=0; k<m; k++)          /*最外层:遍历z点数组*/{/*插值多项式的第一个因子*/pz[k] = coeff[0];       for(j=1; j<n; j++)      /*嵌套:构造多项式(新算式等于上一步的结果加上新因子)*/{term = coeff[j];    /*因子构成:以多项式系数为基础*/for(i=0; i<j; i++)  /*嵌套:新因子以上一步的结果乘以(z[k] - x[i]*/term=term*(z[k] - x[i]);pz[k]=pz[k] + term;}}free(coeff);return 0;
}

 

转载于:https://www.cnblogs.com/idreamo/p/9039000.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/452648.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux中断 - tasklet

一、前言 对于中断处理而言&#xff0c;linux将其分成了两个部分&#xff0c;一个叫做中断handler&#xff08;top half&#xff09;&#xff0c;属于不那么紧急需要处理的事情被推迟执行&#xff0c;我们称之deferable task&#xff0c;或者叫做bottom half&#xff0c;。具体…

数字电视制播设备间的文件交换格式

在现今的数字电视演播室中&#xff0c;设备之间基本上采用信号流连接方式&#xff0c;如SDI、STDI、模拟YUV、VBS等信号流。在非线性编辑系统和播出系统与服务器之间的连接&#xff0c;还有基于MPEG-2传输流等的信号连接方式。基于信号流连接方式的主要特点是&#xff0c;传送时…

oracle 位移运算符,Oracle“(+)”运算符

在Oracle中&#xff0c;()表示JOIN中的“可选”表。 所以在你的查询中&#xff0c;select a.id, b.id, a.col_2, b.col_2, ... from a,b where a.idb.id()这是一个左外加B表与一个表。 就像现代的左连接查询一样。 (它将返回a表的所有数据&#xff0c;而不会丢失在另一边的数据…

什么是实体-联系图(ER图)

实体-联系图&#xff08;ER图&#xff09;数据模型中包含3种相互关联的信息&#xff1a;数据对象、数据对象的属性及数据对象彼此间相互连接的关系。 1.数据对象 数据对象是对软件必须理解的复合信息的抽象。所谓符合信息是指具有一系列不同性质或属性的事物&#xff0c;仅有单…

记录的习惯

记录的习惯 书籍是人类进步的阶梯&#xff0c;承载了人类文明进步的历程。大多数人都写过日记&#xff0c;但不知道有多少人重视过日记。常常我们会用相机记录一些生活中的场景&#xff0c;然后收藏起来&#xff0c;等到若干年后再拿出来看&#xff0c;总能感觉到很温馨很美好。…

Flask爱家租房--发布新房源(保存房屋基本信息)

0.页面展示效果 1.后端代码 api.route("/houses/info", methods["POST"]) login_required def save_house_info():"""保存房屋的基本信息前端发送过来的json数据{"title":"","price":"","ar…

【c#】RabbitMQ学习文档(一)Hello World

一、简介 RabbitMQ是一个消息的代理器&#xff0c;用于接收和发送消息&#xff0c;你可以这样想&#xff0c;他就是一个邮局&#xff0c;当您把需要寄送的邮件投递到邮筒之时&#xff0c;你可以确定的是邮递员先生肯定会把邮件发送到需要接收邮件的人的手里&#xff0c;不…

oracle中如何分页,Oracle中操作分页

mysql中分页的写法&#xff1a;select t.* from tbl_user t order by t.id limit $offset , $perpage$currentPage 1;//当前页码其中后面$sql&#xff1a;with partdata as (select rownum rowno,t.* from tablename t where column1090order by column) select * from partda…

Flask爱家租房--发布新房源(保存房屋图片)

0.页面展示效果 1&#xff09;首先房东填写房屋信息&#xff1b; 2&#xff09;当房东填写发布的房源信息之后&#xff0c;隐藏&#xff08;hide&#xff09;刚才填写信息的界面&#xff0c;同时显示(show)上传房屋图片的界面。 1.后端代码 api.route("/houses/image&q…

数字的处理 :小数点四舍五入

js取float型小数点后两位数的方法 转载 发布时间&#xff1a;2014年01月18日 17:03:32 投稿&#xff1a;shangke 我要评论 js中取小数点后两位方法最常用的就是四舍五入函数了&#xff0c;前面我介绍过js中四舍五入一此常用函数&#xff0c;这里正好用上&#xff0c;下面…

如何成为一名优秀的C程序员

问题的提出 每过一段时间我总会收到一些程序员发来的电子邮件&#xff0c;他们会问我是用什么编程语言来编写自己的游戏的&#xff0c;以及我是如何学习这种编程语言的。因此&#xff0c;我认为在这篇博文里列出一些有关C语言的最佳读物应该能帮到不少人。如果你知道其它的优秀…

CFS调度器

一、前言 随着内核版本的演进&#xff0c;其源代码的膨胀速度也在递增&#xff0c;这让Linux的学习曲线变得越来越陡峭了。这对初识内核的同学而言当然不是什么好事情&#xff0c;满腔热情很容易被当头浇灭。我有一个循序渐进的方法&#xff0c;那就是先不要看最新的内核&#…

Flask爱家租房--发布新房源(总结)

重点总结 学习过程中&#xff0c;发现house_id贯穿两个接口内容&#xff0c;现对后端逻辑部分做以下总结&#xff1a; 1&#xff09;房东首先在前端填写房屋的基本信息&#xff0c;此时通过newhouse.js文件$("#form-house-info").submit(function (e) {…}进行处理&…

关系代数

关系代数是一种抽象的查询语言&#xff0c;它用对关系的运算来表达查询关系代数运算对象是关系运算结果亦为关系关系代数的运算符有两类&#xff1a;集合运算符和专门的关系运算符

设计模式的六大原则

设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更加容易被他人理解、保证代码可靠性。设计模式是代码编制真正工程化&#xff08;工程化即系统化、模块化、规范化的一个过程。指将具有一定规模数量的单个…

作业7

stuNum 201709090072 print(年级是&#xff1a;stuNum[0:4]) print(专业编号是: stuNum[4:9]) print(序号是: stuNum[-3:]) stuNum 440982201812111876 print(所在省市&#xff1a;stuNum[0:2]) print(所在地区&#xff1a;stuNum[2:4]) print(所在县区&#xff1a;stuNum[4:…

linux进程退出没有log,Linux下应用进程消失原因分析-Go语言中文社区

应用部署在Linux环境下&#xff0c;如果出现未知原因导致应用进程被杀(应用日志中没有任何异常现象&#xff0c;日志出现中断现象)&#xff0c;如果对于进程消失原因没有特别明确的方向&#xff0c;可以考虑从系统日志(/var/log/messages)方面查找原因。 命令参考egrep -i kill…

数学是成就卓越开发人员的必备技能

编者按&#xff1a;原文作者Alan Skorkin是一名软件开发人员&#xff0c;他在博客中分享对软件开发相关的心得&#xff0c;其中有很多优秀的文章&#xff0c;本文就是其中一篇&#xff0c;作者认为&#xff1a;成为优秀的开发人员&#xff0c;可以没有数学技能&#xff0c;但成…