用三弯矩法求解三次样条插值函数
数值分析课程设计报告书三次样条插值的三弯矩法

数值分析课程设计报告书院系名称:学生姓名:专业名称:班级:时间:实验一 三次样条插值的三弯矩法一、实验目的已知数据i x ,()i i y f x =,0,,i n =及边界条件()n j x y j j 1,0),(2=,求)(x f 的三次样条插值函数)(x S .要求输出用追赶法解出的弯矩向量0[,,]n M M M =及()(),0,,,0,1,2k i S t i m k ==的值.画出)(x S y =的图形,图形中描出插值点(,)i i x y 及(,())i i t S t 分别用‘o ’和‘*’标记.二、实验原理1.用追赶法求解第二类边界条件的三弯矩方程:0010012111121111[,,]21[,,]26[,,]212[,,]n n n n n n n n n n f x x x M f x x x M M f x x x M f x x x μλμλ------⎡⎤⎡⎤⎡⎤⎢⎥⎢⎥⎢⎥⎢⎥⎢⎥⎢⎥⎢⎥⎢⎥⎢⎥=⎢⎥⎢⎥⎢⎥⎢⎥⎢⎥⎢⎥⎢⎥⎢⎥⎢⎥⎣⎦⎣⎦⎣⎦ 其中1111,,j jj j j j j j j j j h h h x x h h h h μλ-+--===-++.2.得出样条函数表达式:332211111()()()()()6666j j j j j j j j j j j j j j j jx x x x M h x x M h x x S x M M y y h h h h +++++----=++-+-. 3.计算(k)(),0,,,0,1,2i S t i m k ==.三、实验结果所用数据:x=[-2.223,-1.987,-1.8465,-1.292,-1.2266,-1.1056,-0.8662,-0.6594,-0.2671,-0.0452,0.5385,1.2564,1.4398,1.5415,1.7646,1.9678,2.236];y=[0.83995,1.1696,1.3141,1.6992,1.7312,1.7847,1.8708,1.9262,1.9881,1.9997,1.9511,1.7169,1.618,1.5543,1.3871,1.191,0.81662];d2s1= -4.5000;d2sn= -4.8967; %第二种边界条件t=[-2.223,-1.9443,-1.6656,-1.3869,-1.1083,-0.82956,-0.55088,-0.27219,0.0065,0.28519,0.56387,0.84256,1.1212,1.3999,1.6786,2.236]; ;(指定计算点)计算结果:-2.5-2-1.5-1-0.500.51 1.52 2.50.811.21.41.61.82四、实验分析通过实验结果我们,知道三弯矩法求出满足初始条件的三次样条函数,与其他插值函数的构造相比,三次样条插值法的计算量要小得多。
数值计算方法第四章第四节 三次样条

yi f (xi )(i 0,1,...,n) 以及边界点上的一阶导数值f '(x0 ), f '(xn). 求一个三次样条函数S( x)使之满足
S(xi ) yi
(i 1,2,...,n 1)
S(xj ) yj , S'(xj ) f '(xj ) ( j 0, n) 8-
三弯矩插值法的基本思想 ( 1)yi'' f''(xi )未知,但可设S''(xi)Mi,
上的一个分划 ,:ax0x1 xn1xnb 给定节点上函数值f(xi),i0,1,2, ,n。 若函数S(x)满足 (1)S(xi ) yi i 0,1, n; (2)S(x)Ck1[a,b],即在整体上是k-1阶连续的; (3)S(x)在每一个小区间[xi, xi1]是k次多项式
(i 0,1, n1) 则称S(x)为k次样条函数。x1,..., xn1称为内节点, x0, xn称为外节点.
2-
样条是绘图员用于描绘光滑曲线的一种机 械器件,它是一些易弯曲材料制成的窄条或棒条. 或接近图 表上确定的描绘点.“样条函数”这个术语意在 点出这种函数的图象与机械样条画出的曲线很 象.
3-
一.k次样条函数的定义
定义 若函数yf(x)在 [a,b]上连续,对于区间[a,b]
( 4 ) 再 由 三 弯 矩 方 程 边 界 条 件 ( 补 充 两 个 方 程 ) 封 闭 的 方 程 组 , 可 求 出 M i,(i 0 ,1 ,2 ,...,n )9-
1、建立三弯矩方程 在[xi,xi1]上,三次样条函数可表示为 Si(x)ai(xxi )3 bi(xxi )2 ci(xxi )di (i 0, 1,,n1)
三次样条函数三弯矩算法

摘要求函数在给定区间上的定积分,在微积分学中已给出了许多计算方法,但是,在实际问题计算中,往往仅给出函数在一些离散点的值,它的解析表达式没有明显的给出,或者,虽然给出解析表达式,但却很难求得其原函数。
这时我们可以通过数值方法求出函数积分的近似值。
在用近似值代替真实值时,遇到的问题就是近似值的代数精度是否足够。
当代数精度不足够时,很显然提高插值函数的次数是一种方法,但是考虑到数值计算的稳定性,当次数过高时,会出现龙格现象,用增大n的方法来提高数值积代数精度是不可取的。
正如我们所知道的分段线性插值,逼近程度好,但光滑性差。
分段三次Hermite插值,逼近程度好,光滑性也有所提高,但是需要增加更多的条件,不太实用。
因此,我们将介绍一种结合二者的优点的插值方法——三次样条插值。
本实验将介绍三次样条插值的三弯矩算法。
关键词:龙格现象三弯矩算法代数精度分段三次Hermite插值1、实验目的1) 通过本次实验体会并学习三次样条插值的优点。
2) 通过对三次样条插值进行编程实现,提高自己的编程能力。
3) 用实验报告的形式展现,提高自己在写论文方面的能力。
2、算法流程如果已知函数)(x f y =在节点a =x 0<x 1<⋯<x n =b,y i =f (x i ),i =0,1,2,⋯,n 处的函数值和导数值:n i x f y i i ,,2,1,0),( ==如果)(x S 满足条件:1) S (x )是一个分段的三次多项式且i i y x s =)(;2) S (x )在[a,b]具有二阶连续导数。
则称S (x )是三次样条插值函数。
S (x )的具体形式为:其中S i (x)在[x n−1,x n ]上是三次多项式S i (x )=a i x 3+b i x 2+c i x +d i 由插值条件S (x i )=y i ,i=0,1,2,…,n ,得n+1个条件。
边界条件一:S ′(x 0)=y 0′,S ′(x n )=y n ′边界条件二:S ′′(x 0)=y 0′′,S ′′(x n )=y n ′′边界条件三:假定函数y =f(x)是以b-a 为周期的周期函数,这时要求S(x)也是周期函数,即{S (x 0+0)=S(x n −0)S ′(x 0+0)=S ′(x n −0)S ′′(x 0+0)=S ′′(x n +0)()()()()⎪⎪⎩⎪⎪⎨⎧∈∈∈=-]12,121,01,[,...............][,][,n n n x x x x s x x x x s x x x x s x s针对三种边界条件的求解方法的不同,可以分为三转角算法和三弯矩算法,本实验将介绍和学习三转角算法。
三次样条插值

0)
s(xn 0) s(xn 0)
三弯矩插值法
x xi,
x i+1
s”(x) M i , M i+1
记Mi = s″(xi), f(xi)= yi ,考虑它在任一区间[xi, xi+1]上的形式. 根据三次样条的定义可知 , s(x)的二阶导数 s ″(x)在每一个子区
间[xi, xi+1] ( i=0,1,2,,n-1)上都是线性函数.
2 6
M
i
)(xi1
xi
)
(1)
同理在[xi1, xi ]上讨论得
s(xi )
yi xi
yi1 xi1
(
2 6
M
i
1 6 M i1)(xi
xi1)
(2)
因为s( x)连续,所以(1)(2)即
yi1 yi xi1 xi
1 ( 6 M i1
2 6
M i )(xi1
xi )
yi xi
yi1 xi1
(2) (n 1)内节点处连续及光滑性条件:
s(x s( x
j j
0) 0)
s(x j 0) s(x j 0)
j
1,2,...,n
1
s(x j 0) s(x j 0)
对于待定系数a j ,bj , c j .d j j 1,2,...n,即4n个未知系数,
而插值条件为4n 2个,还缺两个,因此须给出两个 条件称为边界条件,有以下三类:
——分段三次插值多项式
分段插值存在着一个缺点,就是会导致插值函数在子区间的端点 (衔接处)不光滑,即导数不连续。
实际应用中,如机翼设计、船体放样等往往要求有二阶光滑度, 即二阶连续导数。早期工程师制图时,把富有弹性的细长木条 (所谓样条SPLINE )用压铁固定在样点上,其它地方让其自 由弯曲,然后画下曲线(称为样条曲线),它实际上是由分段 多项式光滑连接而成,在样点上要求二阶连续可导。
三转角样条插值

三转角样条插值摘要:对于插值多项式的次数问题,人们一般认为:插值多项式的次数越高,精度越高。
比如线性插值的误差就比抛物线插值的误差要大。
但是在20世纪初龙格(Runge )现象说明插值多项式并非次数越高精度越高。
人们利用样条插值来拟合曲线,可以利用足够的的数据点,还有公式简单,运算量节省等好处,其中最常用的样条函数是三次样条。
在课本《现代数字数学与计算》中采用的是三弯矩方法推导得出三次样条插值多项式的计算公式,本文将采用三转角法推出三次样条插值多项式的计算公式,并用其拟合几个函数。
在发现等距节点在拟合不连续函数的结果不让人满意时,使用Chebyshev 插值节点构造不均匀节点来减少其拟合的误差,最后用三转角样条插值函数拟合画出手写字母。
三转角法的理论:对于b t t t a n =<<<=...10,考虑],[2b a C s ∈的三次样条插值函数,使得n i t f f t s i i i ,...,1,0),()(===,且满足第一类边界条件00'0')()(β==t f t s ,n n n t f t s β==)()(''。
验证在区间n i t t i i ,...,2,1],,[1=-上满足)()()()()(11t v t u t q f t p f t s i i i i i i i i i ββ+++=--其中1--=i i i t t h ,)](2[)()(132--+-=i i ii i t t h ht t t p , )](2[)()(321i i ii i t t h h t t t q ---=- ,212)()()(ii i i h t t t t t u ---=, 221)()()(ii i i h t t t t t v --=- ,而 i β可由递推公式)(3)11(31)11(21212112121111ii i i i ii i i i i ii ih f h f h h f h h h h -++++++--+-=+++βββ所确定。
数值分析报告作业-三次样条插值

数值计算方法作业实验4.3 三次样条差值函数实验目的:掌握三次样条插值函数的三弯矩方法。
实验函数:dt ex f xt ⎰∞--=2221)(πx 0.0 0.1 0.2 0.3 0.4 F(x)0.50000.53980.57930.61790.7554求f(0.13)和f(0.36)的近似值实验内容:(1) 编程实现求三次样条插值函数的算法,分别考虑不同的边界条件; (2) 计算各插值节点的弯矩值;(3) 在同一坐标系中绘制函数f(x),插值多项式,三次样条插值多项式的曲线比较插值结果。
实验名称 实验4.3三次样条插值函数(P126)4.5三次样条插值函数的收敛性(P127)实验时间姓名班级学号成绩实验4.5 三次样条差值函数的收敛性实验目的:多项式插值不一定是收敛的,即插值的节点多,效果不一定好。
对三次样条插值函数如何呢?理论上证明三次样条插值函数的收敛性是比较困难的,通过本实验可以证明这一理论结果。
实验内容:按照一定的规则分别选择等距或非等距的插值节点,并不断增加插值节点的个数。
实验要求:(1)随着节点个数的增加,比较被逼近函数和三样条插值函数的误差变化情况,分析所得结果并与拉格朗日插值多项式比较;(2)三次样条插值函数的思想最早产生于工业部门。
作为工业应用的例子,考虑如下例子:某汽车制造商根据三次样条插值函数设计车门曲线,其中一段数据如下:x0 1 2 3 4 5 6 7 8 9 10 ky0.0 0.79 1.53 2.19 2.71 3.03 3.27 2.89 3.06 3.19 3.29 ky 0.8 0.2 k算法描述:拉格朗日插值:错误!未找到引用源。
其中错误!未找到引用源。
是拉格朗日基函数,其表达式为:()∏≠=--=nij j j i ji x x x x x l 0)()(牛顿插值:))...()(](,...,,[....))(0](,,[)0](,[)()(1102101210100----++--+-+=n n n x x x x x x x x x x f x x x x x x x f x x x x f x f x N其中⎪⎪⎪⎪⎪⎪⎩⎪⎪⎪⎪⎪⎪⎨⎧--=--=--=-)/(]),...,[],...,[(]...,[..],[],[],,[)()(],[01102110x x x x x f x x x f x x x f x x x x f x x f x x x f x x x f x f x x f n n n n i k j i k j k j i ji j i j i三样条插值:所谓三次样条插值多项式Sn(x)是一种分段函数,它在节点Xi(a<X0<X1……<Xn<b)分成的每个小区间[x i-1,x i ]上是三次多项式,其在此区间上的表达式如下:],[),6()6(]6)([6)(6)()(111113131i i ii i i i i i i i i i i i i i i i i i x x x h yM h M h h y x M M h h y y h x x Mi h x x M x S -------∈-+-+---+-+-=式中Mi=)(i x S ''.因此,只要确定了Mi 的值,就确定了整个表达式,Mi 的计算方法如下:令⎪⎪⎪⎪⎩⎪⎪⎪⎪⎨⎧=---+=+=+=+--++++++],,[6)(6111111111i i i i i i i i i i i i i i i i i i i ix x x f h y y h y y h h d h h h h h h λμ则Mi 满足如下n-1个方程:1,...2,1,211-==+++-n i d M M M i i i i i i λμ 常用的边界条件有如下几类:(1) 给定区间两端点的斜率m 0,m n ,即n n n m y x S m y x S ='='='=')(,)(000 (2) 给定区间两端点的二阶导数M0,Mn,即n n n M y x S M y x S =''=''=''='')(,)(000 (3) 假设y=f(x)是以b-a 为周期的周期函数,则要求三次样条插值函数S (x )也为周期函数,对S (x )加上周期条件2,1,0),0()0()(0)(=-=+p x S x S n p p对于第一类边界条件有⎪⎪⎩⎪⎪⎨⎧--=+--=+--)(62)(6211001110n n nn nn ih y y mn h M M m h y y h M M对于第二类边界条件有⎩⎨⎧=+=+-nn n n d M M d M M 2210100μλ其中nn n n nn n M u x x f m h d M m x x f h d )1(2]),[(6)1(2)],[(6100001010-+-=-+-=-μλλ那么解就可以为⎥⎥⎥⎥⎥⎥⎥⎥⎦⎤⎢⎢⎢⎢⎢⎢⎢⎢⎣⎡=⎥⎥⎥⎥⎥⎥⎥⎥⎦⎤⎢⎢⎢⎢⎢⎢⎢⎢⎣⎡⎪⎪⎪⎪⎪⎪⎪⎪⎭⎫ ⎝⎛----n n n n n n n d d d d d M M M M M 1210121011...2...............2............................1..2.1......0..2μλμλμλ 对于第三类边界条件,)0()0(,,000-=+==n n n x S x S M M y y ,由此推得0010012d M M M n =-++μλ,其中]),1[],[(6,,101010110n n nn n n x x f x x f h h d h h h h h h --+=+=+=μλ,那么解就可以为: ⎥⎥⎥⎥⎥⎥⎥⎥⎦⎤⎢⎢⎢⎢⎢⎢⎢⎢⎣⎡=⎥⎥⎥⎥⎥⎥⎥⎥⎦⎤⎢⎢⎢⎢⎢⎢⎢⎢⎣⎡⎪⎪⎪⎪⎪⎪⎪⎪⎭⎫ ⎝⎛-------1221012101221100...2.............2..............................2..,,.......,..22n n n n n n n d d d d d M M M M M n μλλμλμμλ 程序代码: 1拉格朗日插值函数Lang.mfunction f=lang(X,Y,xi) %X 为已知数据的横坐标 %Y 为已知数据的纵坐标 %xi 插值点处的横坐标%f 求得的拉格朗日插值多项式的值 n=length(X); f=0; for i=1:n l=1; for j=1:i-1l=l.*(xi-X(j))/(X(i)-X(j)); end ; for j=i+1:nl=l.*(xi-X(j))/(X(i)-X(j));end;%拉格朗日基函数f=f+l*Y(i);endfprintf('%d\n',f)return2 牛顿插值函数newton.mfunction f=newton(X,Y,xi)%X为已知数据的横坐标%Y为已知数据的纵坐标%xi插值点处的横坐标%f求得的拉格朗日插值多项式的值n=length(X);newt=[X',Y'];%计算差商表for j=2:nfor i=n:-1:1if i>=jY(i)=(Y(i)-Y(i-1))/(X(i)-X(i-j+1));else Y(i)=0;endendnewt=[newt,Y'];end%计算牛顿插值f=newt(1,2);for i=2:nz=1;for k=1:i-1z=(xi-X(k))*z;endf=f+newt(i-1,i)*z;endfprintf('%d\n',f)return3三次样条插值第一类边界条件Threch.mfunction S=Threch1(X,Y,dy0,dyn,xi) % X为已知数据的横坐标%Y为已知数据的纵坐标%xi插值点处的横坐标%S求得的三次样条插值函数的值%dy0左端点处的一阶导数% dyn右端点处的一阶导数n=length(X)-1;d=zeros(n+1,1);h=zeros(1,n-1);f1=zeros(1,n-1);f2=zeros(1,n-2);for i=1:n%求函数的一阶差商h(i)=X(i+1)-X(i);f1(i)=(Y(i+1)-Y(i))/h(i);endfor i=2:n%求函数的二阶差商f2(i)=(f1(i)-f1(i-1))/(X(i+1)-X(i-1));d(i)=6*f2(i);endd(1)=6*(f1(1)-dy0)/h(1);d(n+1)=6*(dyn-f1(n-1))/h(n-1);%¸赋初值A=zeros(n+1,n+1);B=zeros(1,n-1);C=zeros(1,n-1);for i=1:n-1B(i)=h(i)/(h(i)+h(i+1));C(i)=1-B(i);endA(1,2)=1;A(n+1,n)=1;for i=1:n+1A(i,i)=2;endfor i=2:nA(i,i-1)=B(i-1);A(i,i+1)=C(i-1);endM=A\d;syms x;for i=1:nSx(i)=collect(Y(i)+(f1(i)-(M(i)/3+M(i+1)/6)*h(i))*(x-X(i))... +M(i)/2*(x-X(i))^2+(M(i+1)-M(i))/(6*h(i))*(x-X(i))^3); digits(4);Sx(i)=vpa(Sx(i));%三样条插值函数表达式endfor i=1:ndisp('S(x)=');fprintf('%s (%d,%d)\n',char(Sx(i)),X(i),X(i+1));endfor i=1:nif xi>=X(i)&&xi<=X(i+1)S=Y(i)+(f1(i)-(M(i)/3+M(i+1)/6)*h(i))*(xi-X(i))+M(i)/2*(xi-X(i))^2+(M(i+1)-M(i))/(6*h(i))*( xi-X(i))^3;endenddisp('xi S');fprintf('%d,%d\n',xi,S);return4 三次样条插值第二类边界条件Threch2.mfunction [Sx]=Threch2(X,Y,d2y0,d2yn,xi)X为已知数据的横坐标%Y为已知数据的纵坐标%xi插值点处的横坐标%S求得的三次样条插值函数的值%d2y0左端点处的二阶导数% d2yn右端点处的二阶导数n=length(X)-1;d=zeros(n+1,1);h=zeros(1,n-1);f1=zeros(1,n-1);f2=zeros(1,n-2);for i=1:n%求一阶差商h(i)=X(i+1)-X(i);f1(i)=(Y(i+1)-Y(i))/h(i);endfor i=2:n%求二阶差商f2(i)=(f1(i)-f1(i-1))/(X(i+1)-X(i-1)); d(i)=6*f2(i);endd(1)=2*d2y0;d(n+1)=2*d2yn;%赋初值A=zeros(n+1,n+1);B=zeros(1,n-1);C=zeros(1,n-1);for i=1:n-1B(i)=h(i)/(h(i)+h(i+1));C(i)=1-B(i);endA(1,2)=0;A(n+1,n)=0;for i=1:n+1A(i,i)=2;endfor i=2:nA(i,i-1)=B(i-1);A(i,i+1)=C(i-1);endM=A\d;syms x;for i=1:nSx(i)=collect(Y(i)+(f1(i)-(M(i)/3+M(i+1)/6)*h(i))*(x-X(i))...+M(i)/2*(x-X(i))^2+(M(i+1)-M(i))/(6*h(i))*(x-X(i))^3);digits(4);Sx(i)=vpa(Sx(i));endfor i=1:ndisp('S(x)=');fprintf('%s (%d,%d)\n',char(Sx(i)),X(i),X(i+1));endfor i=1:nif xi>=X(i)&&xi<=X(i+1)S(i)=Y(i)+(f1(i)-(M(i)/3+M(i+1)/6)*h(i))*(xi-X(i))+M(i)/2*(xi-X(i))^2+(M(i+1)-M(i))/(6*h(i) )*(xi-X(i))^3;endenddisp('xi S');fprintf('%d,%d\n',xi,S);return5插值节点处的插值结果main3.mclearclcX=[0.0,0.1,0.2,0.3,0.4];Y=[0.5000,0.5398,0.5793,0.6179,0.7554];xi=0.13;%xi=0.36;disp('xi=0.13');%disp('xi=0.36');disp('拉格朗日插值结果');lang(X,Y,xi);disp('牛顿插值结果');newton(X,Y,xi);disp('三次样条第一类边界条件插值结果');Threch1(X,Y,0.40,0.36,xi);%0.4,0.36分别为两端点处的一阶导数disp('三次样条第二类边界条件插值结果');Threch2(X,Y,0,-0.136,xi);%0,-0.136分别为两端点处的二阶导数6将多种插值函数即原函数图像画在同一张图上main2.mclearclcX=[0.0,0.1,0.2,0.3,0.4];Y=[0.5000,0.5398,0.5793,0.6179,0.7554];a=linspace(0,0.4,21);NUM=21;L=zeros(1,NUM);N=zeros(1,NUM);S=zeros(1,NUM);B=zeros(1,NUM);for i=1:NUMxi=a(i);L(i)=lang(X,Y,xi);% 拉格朗日插值N(i)=newton(X,Y,xi);%牛顿插值B(i)=normcdf(xi,0,1);%原函数S(i)=Threch1(X,Y,0.4,0.36,xi);%三次样条函数第一类边界条件endplot(a,B,'--r');hold on;plot(a,L,'b');hold on;plot(a,N,'r');hold on;plot(a,S,'r+');hold on;legend('原函数','拉格朗日插值','牛顿插值','三次样条插值',2); hold off7增加插值节点观察误差变化main4.mclear;clc;N=5;%4.5第一问Ini=zeros(1,1001);a=linspace(-1,1,1001);Ini=1./(1+25*a.^2);for i=1:3 %节点数量变化次数N=2*N;t=linspace(-1,1,N+1);%插值节点ft=1./(1+25*t.^2);%插值节点函数值val=linspace(-1,1,101);for j=1:101L(j)=lang(t,ft,val(j));S(j)=Threch1(t,ft,0.074,-0.074,val(j));%三样条第一类边界条件插值endplot(a,Ini,'k')%原函数图象hold onplot(val,L,'r')%拉格朗日插值函数图像hold onplot(val,S,'b')%三次样条插值函数图像str=sprintf('插值节点为%d时的插值效果',N);title(str);legend('原函数','拉格朗日插值','三次样条插值');%显示图例hold offfigureend8车门曲线main5.mclearclcX=[0,1,2,3,4,5,6,7,8,9,10];Y=[0.0,0.79,1.53,2.19,2.71,3.03,3.27,2.89,3.06,3.19,3.29];dy0=0.8;dyn=0.2;n=length(X)-1;d=zeros(n+1,1);h=zeros(1,n-1);f1=zeros(1,n-1);f2=zeros(1,n-2);for i=1:nh(i)=X(i+1)-X(i);f1(i)=(Y(i+1)-Y(i))/h(i);endfor i=2:nf2(i)=(f1(i)-f1(i-1))/(X(i+1)-X(i-1));d(i)=6*f2(i);endd(1)=6*(f1(1)-dy0)/h(1);d(n+1)=6*(dyn-f1(n-1))/h(n-1); A=zeros(n+1,n+1); B=zeros(1,n-1);C=zeros(1,n-1);for i=1:n-1B(i)=h(i)/(h(i)+h(i+1));C(i)=1-B(i);endA(1,2)=1;A(n+1,n)=1;for i=1:n+1A(i,i)=2;endfor i=2:nA(i,i-1)=B(i-1);A(i,i+1)=C(i-1);endM=A\d;x=zeros(1,n);S=zeros(1,n);for i=1:nx(i)=X(i)+0.5;S(i)=Y(i)+(f1(i)-(M(i)/3+M(i+1)/6)*h(i))*(x(i)-X(i))+M(i)/2*(x(i)-X(i))^2+(M(i+1)-M(i))/(6* h(i))*(x(i)-X(i))^3;endplot(X,Y,'k'); hold on;plot(x,S,'o');title('三次样条插值效果图');legend('已知插值节点','三次样条插值');hold off实验结果:4.31计算插值节点处的函数值xi=0.13时Xi=0.36时2将多种插值函数即原函数图像画在同一张图上4.5.1增加插值节点观察误差变化从上面三张图可以看出增加插值节点并不能改善差之效果4.5.2 车门曲线。
三次样条插值计算算法

/* 三次样条插值计算算法*/#include "math.h "#include "stdio.h "#include "stdlib.h "/*N:已知节点数N+1R:欲求插值点数R+1x,y为给定函数f(x)的节点值{x(i)} (x(i) <x(i+1)) ,以及相应的函数值{f(i)} 0 <=i <=NP0=f(x0)的二阶导数;Pn=f(xn)的二阶导数u:存插值点{u(i)} 0 <=i <=R求得的结果s(ui)放入s[R+1] 0 <=i <=R返回0表示成功,1表示失败*/int SPL(int N,int R,double x[],double y[],double P0,double Pn,double u[],double s[]){/*声明局部变量*/double *h; /*存放步长:{hi} 0 <=i <=N-1 */double *a; /*存放系数矩阵{ai} 1 <=i <=N ;分量0没有利用*/ double *c; /*先存放系数矩阵{ci} 后存放{Bi} 0 <=i <=N-1 */double *g; /*先存放方程组右端项{gi} 后存放求解中间结果{yi} 0 <=i <=N */double *af; /*存放系数矩阵{a(f)i} 1 <=i <=N ;*/double *ba; /*存放中间结果0 <=i <=N-1*/double *m; /*存放方程组的解{m(i)} 0 <=i <=N ;*/int i,k;double p1,p2,p3,p4;/*分配空间*/if(!(h=(double*)malloc(N*sizeof(double)))) exit(1);if(!(a=(double*)malloc((N+1)*sizeof(double)))) exit(1);if(!(c=(double*)malloc(N*sizeof(double)))) exit(1);if(!(g=(double*)malloc((N+1)*sizeof(double)))) exit(1);if(!(af=(double*)malloc((N+1)*sizeof(double)))) exit(1);if(!(ba=(double*)malloc((N)*sizeof(double)))) exit(1);if(!(m=(double*)malloc((N+1)*sizeof(double)))) exit(1);/*第一步:计算方程组的系数*/for(k=0;k <N;k++)h[k]=x[k+1]-x[k];for(k=1;k <N;k++)a[k]=h[k]/(h[k]+h[k-1]);for(k=1;k <N;k++)c[k]=1-a[k];for(k=1;k <N;k++)g[k]=3*(c[k]*(y[k+1]-y[k])/h[k]+a[k]*(y[k]-y[k-1])/h[k-1]); c[0]=a[N]=1;g[0]=3*(y[1]-y[0])/h[0]-P0*h[0]/2;g[N]=3*(y[N]-y[N-1])/h[N-1]+Pn*h[N-1]/2;/*第二步:用追赶法解方程组求{m(i)} */ba[0]=c[0]/2;g[0]=g[0]/2;for(i=1;i <N;i++){af[i]=2-a[i]*ba[i-1];g[i]=(g[i]-a[i]*g[i-1])/af[i];ba[i]=c[i]/af[i];}af[N]=2-a[N]*ba[N-1];g[N]=(g[N]-a[N]*g[N-1])/af[N];m[N]=g[N]; /*P110 公式:6.32*/ for(i=N-1;i> =0;i--)m[i]=g[i]-ba[i]*m[i+1];/*第三步:求值*/for(i=0;i <=R;i++){/*判断u(i)属于哪一个子区间,即确定k */if(u[i] <x[0] || u[i]> x[N]){/*释放空间*/free(h);free(a);free(c);free(g);free(af);free(ba);free(m);return 1;}k=0;while(u[i]> x[k+1])k++;//p1=(h[k]+2*(u[i]-x[k])*pow((u[i]-x[k+1]),2)*y[k])/pow(h[k],3); //p2=(h[k]-2*(u[i]-x[k+1])*pow((u[i]-x[k]),2)*y[k+1])/pow(h[k],3);p1=(h[k]+2*(u[i]-x[k]))*pow((u[i]-x[k+1]),2)*y[k]/pow(h[k],3);p2=(h[k]-2*(u[i]-x[k+1]))*pow((u[i]-x[k]),2)*y[k+1]/pow(h[k],3); p3=(u[i]-x[k])*pow((u[i]-x[k+1]),2)*m[k]/pow(h[k],2);p4=(u[i]-x[k+1])*pow((u[i]-x[k]),2)*m[k+1]/pow(h[k],2);s[i]=p1+p2+p3+p4;}/*释放空间*/free(h);free(a);free(c);free(g);free(af);free(ba);free(m);return 0;}void main(){int N,R;double *x,*y,*u,*s;double P0,Pn;int i;/*验证算法:*/N=7;R=6;/*分配空间*/if(!(x=(double*)malloc((N+1)*sizeof(double)))){printf( "malloc error!\n ");exit(1);}if(!(y=(double*)malloc((N+1)*sizeof(double)))){printf( "malloc error!\n ");exit(1);}if(!(u=(double*)malloc((R+1)*sizeof(double)))){printf( "malloc error!\n ");exit(1);}if(!(s=(double*)malloc((R+1)*sizeof(double)))){printf( "malloc error!\n ");exit(1);}x[0]=0.5;x[1]=0.7;x[2]=0.9;x[3]=1.1;x[4]=1.3;x[5]=1.5;x[6]=1.7;x[7]=1.9;y[0]=0.4794;y[1]=0.6442;y[2]=0.7833;y[3]=0.8912;y[4]=0.9636;y[5]=0.9975;y[6]=0.9917;y[7]=0.9 463;u[0]=0.6;u[1]=0.8;u[2]=1.0;u[3]=1.2;u[4]=1.4;u[5]=1.6;u[6]=1.8;P0=-0.4794;Pn=-0.9463;if(!SPL( N, R, x, y, P0, Pn, u, s)){/*打印结果*/printf( "\nx= ");for(i=0;i <=N;i++)printf( "%8.1f ",x[i]);printf( "\ny= ");for(i=0;i <=N;i++)printf( "%8.4f ",y[i]);printf( "\n\nu= ");for(i=0;i <=R;i++)printf( "%9.2f ",u[i]);printf( "\ns= ");for(i=0;i <=R;i++)printf( "%9.5f ",s[i]);printf( "\nsin= ");for(i=0;i <=R;i++)printf( "%9.5f ",sin(u[i]));}/*释放空间*/free(x);free(y);free(u);free(s);}/* 测试数据来自课本55页例5 《数值分析》清华大学出版社第四版*/ //输入327.7 4.128 4.329 4.130 3.013.0 -4.0//输出输出三次样条插值函数:1: [27.7 , 28]13.07*(x - 28)^3 + 0.22*(x - 27.7)^3+ 14.84*(28 - x) + 14.31*(x - 27.7)2: [28 , 29]0.066*(29 - x)^3 + 0.1383*(x - 28)^3+ 4.234*(29 - x) + 3.962*(x - 28)3: [29 , 30]0.1383*(30 - x)^3 - 1.519*(x - 29)^3+ 3.962*(30 - x) + 4.519*(x - 29)//三次样条插值函数#include<iostream>#include<iomanip>using namespace std;const int MAX = 50;float x[MAX], y[MAX], h[MAX];float c[MAX], a[MAX], fxym[MAX];float f(int x1, int x2, int x3){float a = (y[x3] - y[x2]) / (x[x3] - x[x2]);float b = (y[x2] - y[x1]) / (x[x2] - x[x1]);return (a - b)/(x[x3] - x[x1]);} //求差分void cal_m(int n){ //用追赶法求解出弯矩向量M……float B[MAX];B[0] = c[0] / 2;for(int i = 1; i < n; i++)B[i] = c[i] / (2 - a[i]*B[i-1]);fxym[0] = fxym[0] / 2;for(i = 1; i <= n; i++)fxym[i] = (fxym[i] - a[i]*fxym[i-1]) / (2 - a[i]*B[i-1]);for(i = n-1; i >= 0; i--)fxym[i] = fxym[i] - B[i]*fxym[i+1];}void printout(int n);int main(){int n,i; char ch;do{cout<<"Please put in the number of the dots:";cin>>n;for(i = 0; i <= n; i++){cout<<"Please put in X"<<i<<':';cin>>x[i]; //cout<<endl;cout<<"Please put in Y"<<i<<':';cin>>y[i]; //cout<<endl;}for(i = 0; i < n; i++) //求步长h[i] = x[i+1] - x[i];cout<<"Please 输入边界条件\n 1: 已知两端的一阶导数\n 2:两端的二阶导数已知\n 默认:自然边界条件\n";int t;float f0, f1;cin>>t;switch(t){case 1:cout<<"Please put in Y0\' Y"<<n<<"\'\n";cin>>f0>>f1;c[0] = 1; a[n] = 1;fxym[0] = 6*((y[1] - y[0]) / (x[1] - x[0]) - f0) / h[0];fxym[n] = 6*(f1 - (y[n] - y[n-1]) / (x[n] - x[n-1])) / h[n-1];break;case 2:cout<<"Please put in Y0\" Y"<<n<<"\"\n";cin>>f0>>f1;c[0] = a[n] = 0;fxym[0] = 2*f0; fxym[n] = 2*f1;break;default:cout<<"不可用\n";//待定};//switchfor(i = 1; i < n; i++)fxym[i] = 6 * f(i-1, i, i+1);for(i = 1; i < n; i++){a[i] = h[i-1] / (h[i] + h[i-1]);c[i] = 1 - a[i];}a[n] = h[n-1] / (h[n-1] + h[n]);cal_m(n);cout<<"\n输出三次样条插值函数:\n";printout(n);cout<<"Do you to have anther try ? y/n :";cin>>ch;}while(ch == 'y' || ch == 'Y');return 0;}void printout(int n){cout<<setprecision(6);for(int i = 0; i < n; i++){cout<<i+1<<": ["<<x[i]<<" , "<<x[i+1]<<"]\n"<<"\t";/*cout<<fxym[i]/(6*h[i])<<" * ("<<x[i+1]<<" - x)^3 + "<<<<" * (x - "<<x[i]<<")^3 + "<<(y[i] - fxym[i]*h[i]*h[i]/6)/h[i]<<" * ("<<x[i+1]<<" - x) + "<<(y[i+1] - fxym[i+1]*h[i]*h[i]/6)/h[i]<<"(x - "<<x[i]<<")\n";cout<<endl;*/float t = fxym[i]/(6*h[i]);if(t > 0)cout<<t<<"*("<<x[i+1]<<" - x)^3";else cout<<-t<<"*(x - "<<x[i+1]<<")^3";t = fxym[i+1]/(6*h[i]);if(t > 0)cout<<" + "<<t<<"*(x - "<<x[i]<<")^3";else cout<<" - "<<-t<<"*(x - "<<x[i]<<")^3";cout<<"\n\t";t = (y[i] - fxym[i]*h[i]*h[i]/6)/h[i];if(t > 0)cout<<"+ "<<t<<"*("<<x[i+1]<<" - x)";else cout<<"- "<<-t<<"*("<<x[i+1]<<" - x)";t = (y[i+1] - fxym[i+1]*h[i]*h[i]/6)/h[i];if(t > 0)cout<<" + "<<t<<"*(x - "<<x[i]<<")";else cout<<" - "<<-t<<"*(x - "<<x[i]<<")";cout<<endl<<endl;}cout<<endl;}。
2[1].7三次样条插值
![2[1].7三次样条插值](https://img.taocdn.com/s3/m/af64461fff00bed5b9f31dc1.png)
即
lim S ( x ) = lim S ( x ) lim S ′ ( x) = lim S ′ ( x) = m lim S ′′( x) = lim S ′′ ( x) S ′( x ) = f ′ S ′( x ) = f ′ 或
将(13)式化为矩阵形式
2 λ2
µ1 λ3
2
µ2 λ4
2
µ3
2 O O O
λn − 2
λn − 1
O 2
m1 g 1 − λ1 f 0′ m2 g2 g3 m3 M = M M M µ n − 2 mn − 2 gn−2 2 mn − 1 g n − 1 − µ n − 1 f n′
共4 n − 2个条件
′ ′ lim S k′( x ) = lim S k′− 1 ( x ) + −
S k ( x )是[ xk , xk + 1 ]上的三次样条插值多项式, 应有4个待定的系数 即要确定S ( x )必须确定4n个待定的系数
少两个条件
并且我们不能只对插值函数在中间节点的状态进行限制 也要对插值多项式在两端点的状态加以要求 也就是所谓的边界条件: 第一类(一阶)边界条件: 第二类(二阶)边界条件 第三类(周期)边界条件
f(x) H(x) S(x)
二、三次样条插值多项式
a ≤ x0 , x1 ,L , xn ≤ b为区间[ a , b ]的一个分割 如果函数f ( x )在节点x0 , x1 ,L , xn处的函数值为
f ( x j ) = y j , j = 0 ,1,L , n 如果S ( x )是f ( x )的三次样条插值函数, 则其必满足