三次样条插值的C程序(很全啊)
第三章 插值法 三次样条插值
问题
分段低次插值
在处理实际问题时,总是希望将所得到的数据点用得越多越好。
最简单的方法是用直线将函数值点直接连接。
分段低次插值
基本思想:用分段低次多项式来代替单个多项式。
具体作法:(1) 把整个插值区间分割成多个小区间;
(2) 在每个小区间上作低次插值多项式;
(3) 将所有插值多项式拼接整一个多项式。
优点:公式简单、运算量小、稳定性好、收敛性…
缺点:节点处的导数不连续,失去原函数的光滑性。
三次样条函数
样条函数
由一些按照某种光滑条件分段拼接起来的多项式组成的函数。
最常用的样条函数为三次样条函数,即由三次多项式组成,满足处处有二阶连续导数。
定义设节点a =x 0< x 1 < …< x n -1 < x n =b ,若函数
在每个小区间[x i , x i +1 ]上是三次多项式,则称其为三次样条函数。
如果同时满足s (x i ) = f (x i ) (i = 0, 1, 2, …, n ),则称s (x ) 为f (x ) 在[a , b ]上的三次样条函数。
],[)(2b a C x s ∈
利用线性插值公式,即可得的表达式:
求导得:
即:
:第一类边界条件(缺省边界条件)。
三次样条插值算法C++实现
三次样条插值算法C++实现三次样条插值算法1 总体说明三次样条插值算法是⼀种计算量和效果都⽐较理想的插值算法。
关于三次样条插值算法的原理这⾥不做过多的解释,下⾯的代码是我在⽹上收集了两种C++实现版本的基础上⾃⼰整合的⼀个版本。
由于本⼈刚接触C++不久,⽔平有限。
没有使⽤模板机制将代码做的更通⽤。
关于算法实现有下⾯⼏点说明。
1. 所有有关的类都被包含到SplineSpace命名空间中。
2. SplineSpace中⼀个有三个类分别是异常类(SplineFailure),接⼝类(SplineInterface)和实现类(Spline)。
有⼀个枚举类型说明边界条件(BoundaryCondition),取值为:GivenFirstOrder和GivenSecondOrder。
分别对应I型边界条件和II型边界条件。
3. 接⼝类定义了Spline在实现的过程中必须要有的三个⽅法:单点插值、多点插值和⾃动⽣成插值序列。
4. 异常类是可能被实现类抛出的类,如果在实现类的运⾏过程中出现了已知数据过少构造失败、使⽤了外插值、设定输出点数过少等⾏为会抛出该类。
因此应该将插值的过程⽤try...catch(SplineFailure sf)包裹起来。
如:double x0[2]={1,2};double y0[2]={3,4};try{SplineInterface* sp = new Spline(x0,y0,2);//...}catch(SplineFailure sf){cout<<sf.GetMessage()<<endl;}上⾯代码就会抛出异常并显⽰“构造失败,已知点数过少”。
2 插值⽅法调⽤2.1单点插值调⽤⽅法如下:#include <iostream>#include "Spline.h"using namespace std;using namespace SplineSpace;int main(void){//单点插值测试double x0[5]={1,2,4,5,6}; //已知的数据点double y0[5]={1,3,4,2,5};try{//Spline sp(x0,y0,5,GivenSecondOrder,0,0);SplineInterface* sp = new Spline(x0,y0,5); //使⽤接⼝,且使⽤默认边界条件double x=4.5;double y;sp->SinglePointInterp(x,y); //求x的插值结果ycout<<"x="<<x<<"时的插值结果为:"<<y<<endl;}catch(SplineFailure sf){cout<<sf.GetMessage()<<endl;}getchar(); //程序暂停}此时屏幕会输出"x=4.5时的插值结果为2.71107"。
(完整)三次样条插值的C程序(很全啊)
三次样条插值 C/C++程序(自己整理的) 具体推导看书<<数值分析〉〉 code:#include <iostream> using namespace std;(完整)三次样条插值的 C 程序(很全啊)const int MAXN = 100;int n; double x[MAXN], y[MAXN]; //下标从 0。
n double alph[MAXN], beta[MAXN], a[MAXN], b[MAXN]; double h[MAXN]; double m[MAXN]; //各点的一阶导数;inline double sqr(double pa) { return pa * pa;}double sunc(double p, int i) {[i]return (1 + 2 * (p — x[i]) / (x[i + 1] - x[i])) * sqr((p - x[i + 1]) / (x[i + 1] — x[i])) * y+ (1 + 2 * (p — x[i + 1]) / (x[i] - x[i + 1])) * sqr((p - x[i]) / (x[i + 1] — x [i])) * y[i + 1]+ (p - x[i]) * sqr((p — x[i + 1]) / (x[i] - x[i + 1])) * m[i] + (p — x[i + 1]) * sqr((p — x[i]) / (x[i + 1] — x[i])) * m[i + 1]; }int main() { int i, j;double xx;(完整)三次样条插值的 C 程序(很全啊)freopen("threeInsert.in", "r", stdin);scanf(”%d", &n);for (i = 0; i <= n; i++) scanf(”%lf%lf”, &x[i], &y[i]);// scanf("%lf%lf”, &m[0], &m[n]);for (i = 0; i <= n - 1; i++) h[i] = x[i + 1] - x[i];//第一种边界条件//alph[0] = 0; alph[n] = 1; beta[0] = 2 * m[0]; beta[n] = 2 * m[n];//第二种边界条件alph[0] = 1; alph[n] = 0; beta[0] = 3 * (y[1] — y[0]) / h[0]; beta[n] = 3 * (y[n] - y[n — 1] / h [n — 1]);for (i = 1; i 〈= n - 1; i++) { alph[i] = h[i — 1] / (h[i - 1] + h[i]); beta[i] = 3 * ((1 - alph[i]) * (y[i] — y[i — 1]) / h[i - 1] + alph[i] * (y[i + 1] — y[i]) / h[i]);} a[0] = — alph[0] / 2; b[0] = beta[0] / 2;for (i = 1; i <= n; i++) { a[i] = — alph[i] / (2 + (1 — alph[i]) * a[i — 1]); b[i] = (beta[i] - (1 — alph[i]) * b[i - 1]) / (2 + (1 - alph[i]) * a[i — 1]);} m[n + 1] = 0;for (i = n; i 〉= 0; i--) { m[i] = a[i] * m[i + 1] + b[i];} scanf("%lf”, &xx);for (i = 0; i < n; i++) { if (xx 〉= x[i] && xx <= x[i + 1]) break;} printf(”%lf\n", sunc(xx, i));return 0; }(完整)三次样条插值的 C 程序(很全啊)#include<iostream〉 #include<iomanip〉 using namespace std;const int MAX = 50; float x[MAX], y[MAX], h[MAX];//变量设置:x 为各点横坐标;y 为各点纵坐标;h 为步长 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++)(完整)三次样条插值的 C 程序(很全啊)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〈〈"请输入已知断点个数:”;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;}(完整)三次样条插值的 C 程序(很全啊)for(i = 0; i < n; i++) //求步长;其数组值较之 x,y 个数少一 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";//显示数据为 Y0' 至 Yn’,即断点的一阶导数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”;//显示数据为 Y0” 至 Yn”,即断点的二阶导数 cin>>f0>>f1; c[0] = a[n] = 0; fxym[0] = 2*f0; fxym[n] = 2*f1; break; default:cout<<"不可用\n";//待定};//switch(完整)三次样条插值的 C 程序(很全啊)for(i = 1; i 〈 n; i++)fxym[i] = 6 * f(i—1, i, i+1);//调用差分函数(only!)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);//调用弯矩函数(only!)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);//通过操作器 setprecision()设置有效位数;其为头文件 〈iomanip。
第5章-3-三次样条插值PPT课件
(x
a)
m
m次截断多项式
a
.
7
定理5.5 任意s(x)∈Sm(x1,x2,…,xn)均可唯一地表示为
n
s(x)pm(x) cj(xxj)m , x (4-31) j1
其中pm(x)∈Pm,cj(j=1,2,…,n)为实数。
定理5.6 为使s(x)∈Sm(x1,x2,…,xn),必须且只须存在pm(x)∈Pm
8
例1 验证分片多项式是三次样条函数。
1 2x
x 3
S ( x) 2825x9x2x3 3x1
2619x3x2x3 1x0
2619x3x2
0 x
解 利用上面的定理(光滑因子)验证.
(x 3)3,
2(x 1)3,
x3,
所以由定理5.5可知该函数为三次样条函数.
例,设
x3x2
0x1
S(x) a3xb2 xc x11x2
信息;
样? ?条?插插值值::(样条函数—满足一定光滑性的分段多项式)。 局部性好, 满足一定光滑性, 收敛性保证, 只需要函数值
信息。
.
2
样条函数是一个重要的逼近工具,在插值、数值微分、曲 线拟合等方面有着广泛的应用。
定义5.3 对区间(-∞,+∞)的一个分割:
: x 1 x 2 x n ,
n
p n (x )p n 1 (x ) c n (x x n )m p0(x) cj(xxj)m j1
为了便于表示分段信息, 引进截断多项式:
(x a)m
(x a)m , x a,
0, x a,
(5-30)
易见
(x
a)
m
∈Cm-1(-∞,+∞)
三次样条插值
三次样条插值C++数值算法(第二版)3.3 三次样条插值给定一个列表显示的函数yi=y(xi),i=0,1,2,...,N-1。
特别注意在xj和xj+1之间的一个特殊的区间。
该区间的线性插值公式为(3.3.1)式和(3.3.2)式是拉格朗日插值公式(3.1.1)的特殊情况。
因为它是(分段)线性的,(3.3.1)式在每一区间内的二阶导数为零,在横坐标为xj处的二阶导数不定义或无限。
三次样条插值的目的就是要得到一个内插公式,不论在区间内亦或其边界上,其一阶导数平滑,二阶导数连续。
做一个与事实相反的个假设,除yi的列表值之外,我们还有函数二阶导数y"的列表值,即一系列的yi"值,则在每个区间内,可以在(3.3.1)式的右边加上一个三次多项式,其二阶导数从左边的yj"值线性变化到右边的yj+1"值,这么做便得到了所需的连续二阶导数。
如果还将三次多项式构造在xj和xj+1处为零,则不会破坏在终点xj和xj+1处与列表函数值yj和yj+1的一致性。
进行一些辅助计算便可知,仅有一种办法才能进行这种构造,即用注意,(3.3.3)式和(3.3.4)式对自变量x的依赖,是完全通过A和B对x的线性依赖,以及C和D(通过A和B)对x的三次依赖而实现。
可以很容易地验证,y"事实上是该插值多项式的二阶导数。
使用ABCD的定义对x求(3.3.3)式的导数,计算dA/dx dB/dx dC/dx dD/dx,结果为一阶导数因为x=xj是A=1,x=x(i+1)时A=0,而B正相反,则(3.3.6)式表明y"恰为列表函数的二阶导数。
而且该二阶导数在两个区间(xj-1, xj)和(xj, xj+1)上是连续的。
现在唯一的问题是,假设yj"是已知的。
而实际上并不知道。
然而,仍不要求从(3.3.5)式算出的一阶导数在两个区间的边界处是连续的。
三次样条的关键思想就在于要求这种连续性,并用它求得等式的二阶导数yi"。
样条函数及三次样条插值PPT课件
(x)
lim
x xk
Sk 1( x)
lim
x
x
k
Sk (x)
lim
x
x
k
Sk1( x)
k 1,2,,n 1
------(4)
lim
x
x
k
Sk( x)
lim
x
x
k
Sk1( x)
共4n 2个条件
5
Sk (x)是[xk , xk 1 ]上的三次样条插值多项式,应有4个待定的系数 即要确定S(x)必须确定4n个待定的系数 少两个条件 并且我们不能只对插值函数在中间节点的状态进行限制 也要对插值多项式在两端点的状态加以要求 也就是所谓的边界条件:
例. 使用不同的插值方法于函数
y
1
1 x2
x [5,5]
最后,介绍一个有用的结论
定理 . 设f (x) C 2[a,b], S(x)是以xk (k 0,1,, n)
为节点, 满足任意边界条件的三次样条插值函数,
设hi
xi 1
xi
,
h
max
0in1
hi
,
min
0in1
hi
,
则当 h
c 时
S(x)和S(x)在[a,b]上一致收敛到f (x)和f (x)
------(6)
13
由(11)式,可知
S0( x0
)
6( x0
x1 h03
2 x0
) ( y1
y0 )
6 x0
2 x0 h02
4 x1
m0
6 x0
4 x0 h02
2 x1
m1
6 h02
(
基于VC++的三次样条插值
三次样条插值本程序在VC++6.0中,利用MFC程序窗口的View类的OnDraw函数绘制函数图像。
VC++源程序(程序名(空间):Spline.dsw):在CSplineView.cpp源文件中定义数组长度:#define MAX_NUMBER 20 //定义数组长度在CSplineView.h头文件中的CSplineView类中初始化两端点导数值df0,dfn及绘制函数时描点步长x0:df0=0.8;dfn=0.2;x0=0.1;在CSplineView.cpp源文件中的OnDraw函数体中添加如下代码:double h[MAX_NUMBER],f[MAX_NUMBER],lamda[MAX_NUMBER],miu[MAX_NUMBER],e[MAX_NUMBER],b[MAX_NUMBER],*m,A[MAX_NUMBER][MAX_NUMBER];//定义步长h,差分f,λ,μ,e,b,m及解m值的矩阵Adouble d[MAX_NUMBER],u[MAX_NUMBER],l[MAX_NUMBER];//定义追赶法中的变量d,u,ldouble x[MAX_NUMBER]={0,1,2,3,4,5,6,7,8,9,10};//初始化x变量double y[MAX_NUMBER]={2.51,3.30,4.04,4.70,5.22,5.54,5.78,5.40,5.57,5.70,5.80};//初始化y变量int n=10,i,j; //n同公式中的nfor(i=0;i<n;i++) //初始化h,f{h[i]=x[i+1]-x[i]; //步长f[i]=(y[i+1]-y[i])/h[i]; //差分}for(i=1;i<n;i++) //初始化lamda,miu,e,b{lamda[i]=h[i]/(h[i-1]+h[i]);miu[i]=h[i-1]/(h[i-1]+h[i]);e[i]=3*(lamda[i]*f[i-1]+miu[i]*f[i]);if(i>1&&i<(n-1))b[i]=e[i];}b[1]=e[1]-lamda[1]*df0;b[n-1]=e[n-1]-miu[n-1]*dfn;for(i=1;i<n;i++) //初始化m系数矩阵Afor(j=1;j<n;j++){if(i==j)A[i][j]=2;else if(i-j==1)A[i][j]=lamda[i];else if(j-i==1)A[i][j]=miu[i];elseA[i][j]=0;}m=spline.Thomas(n,d,u,b,l,A); //将追赶法算出的值附给数组m(以指针形式)m[0]=df0;m[n]=dfn;//下面将插值函数s(x)各插值点导数值(m)写入文件ofstream table1;table1.open("c:\\table_m.txt");for(i=0;i<=n;i++){table1<<m[i]<<" ";}//以下为程序中使用到的函数定义//追赶法(Thomas方法)函数double *CSplineView::Thomas(int n, double *d,double *u,double *b,double *l,double (*A)[MAX_NUMBER]) //各参数名与主程序变量名一一对应{static double x[MAX_NUMBER];double y[MAX_NUMBER];int i=0,j=0;u[1]=*(*(A+1)+1);y[1]=b[1];for(i=1;i<n;i++) //追{d[i]=*(*(A+i)+i+1);l[i+1]=*(*(A+i+1)+i)/u[i];u[i+1]=*(*(A+i+1)+i+1)-l[i+1]*d[i];y[i+1]=b[i+1]-l[i+1]*y[i];}for(i=n-1;i>0;i--) //赶x[i]=(y[i]-d[i]*x[i+1])/u[i];x[n-1]=y[n-1]/u[n-1];return x;}//样条插值函数(分段)double CSplineView::s(int k,double X,double x[MAX_NUMBER],double h[MAX_NUMBER],double y[MAX_NUMBER],double m[MAX_NUMBER]){double s;s=(X-x[k+1])*(X-x[k+1])*(h[k]+2*(X-x[k]))*y[k]/(h[k]*h[k]*h[k])+(X-x[k])*(X-x[k])*(h[k ]+2*(x[k+1]-X))*y[k+1]/(h[k]*h[k]*h[k])+(X-x[k+1])*(X-x[k+1])*(X-x[k])*m[k]/(h[k]*h[k])+(X -x[k])*(X-x[k])*(X-x[k+1])*m[k+1]/(h[k]*h[k]); //定义样条插值函数return s;}此处忽略VC++中绘制函数的代码,运行程序后绘制的图如下:打开“c:\table_m ”,发现m 的值为:0.8 0.771486 0.704056 0.612289 0.386786 0.360566 -0.149051 -0.184361 0.256496 0.0583759 0.2求方程x 3-3x-1=0在2附近的根1、 Newton 迭代法在VC++6.0中用WIN32控制台程序,输入以下代码:#include "stdafx.h"#include "math.h"#include "iostream.h"double f(double x); //声明需求根的方程f(x)int main(int argc, char* argv[]){double x0=2,xk,yk; //迭代初值2,yk 为前一次迭代值double e=0.01; //保证精确到4位有效数字的e 的取值int i=0;xk=x0; //赋迭代初值yk=x0-2*e; //将yk 赋一初值使下面初始循环条件满足while(fabs(xk-yk)>=e) //迭代循环{yk=xk; //将前一次的xk 值赋给ykxk=xk-f(xk)/(3*xk*xk-3); //Newton 迭代 插值后绘制样条连接插值点的折线插值函数与折线的重叠效果i++; //迭代次数计数器cout<<xk<<" "<<f(xk)<<endl; //输出迭代过程}cout<<"结果为:"<<endl<<xk<<endl; //输出迭代结果cout<<"迭代次数:"<<endl<<i<<endl; //输出迭代次数return 0;}double f(double x) //定义求根函数f(x)=x3-3x-1 {return pow(x,3)-3*x-1;}运行结果如下:2、弦割法在VC++6.0中用WIN32控制台程序,输入以下代码:#include "stdafx.h"#include "iostream.h"#include "math.h"double f(double x);int main(int argc, char* argv[]){double x0=2,x1=1.9,xk,xk_1,temp;//定义初始值x0,x1及迭代过程中需要的变量xk,xk_1,tempdouble e=0.01; //保证精确到4位有效数字的e的取值int i=0;xk=x1; //初始化xkxk_1=x0; //初始化xk_1while(fabs(xk-xk_1)>e) //迭代循环{temp=xk; //以下3行为弦割法算法xk=xk-f(xk)/(f(xk)-f(xk_1))*(xk-xk_1);xk_1=temp;i++; //迭代次数计数器cout<<xk<<" "<<f(xk)<<endl; //输出迭代过程}cout<<"计算结果为:"<<endl<<xk<<endl; //输出计算结果cout<<"迭代次数为:"<<endl<<i<<endl; //输出迭代次数return 0;}double f(double x) //定义求根函数f(x)=x3-3x-1 {return pow(x,3)-3*x-1;}运行结果如下:。
数值计算中完备三次样条插值程序
C++程序# include <iostream.h>int s(intn,double *x,double b){int t;for (inti=0;i<9;i++){if(b<=x[i+1]&&b>x[i])t=i;}return t;}void main(){int n;cout<<"输入待求阶数:";cin>>n;double *x,*fx,*h,*m,*b,*d,dfa,dfb;x=new double[n+1];fx=new double[n+1];h=new double[n];b=new double[n];d=new double[n+1];m=new double[n+1];cout<<"输入x:";for(inti=0;i<(n+1);i++)cin>>x[i];cout<<"输入fx:";for(i=0;i<(n+1);i++)cin>>fx[i];cout<<"输入dfa与dfb:";cin>>dfa>>dfb;for(i=0;i<n;i++)h[i]=x[i+1]-x[i];for(i=0;i<n;i++)b[i]=(fx[i+1]-fx[i])/h[i];d[0]=b[0]-dfa;d[n]=dfb-b[n-1];for(i=1;i<n;i++)d[i]=b[i]-b[i-1];double*A1,*A2,*A3,*A4;double *a,*e,*c,*t,*p,*q,*y;a=new double[n+1];c=new double[n+1];e=new double[n+1];t=new double[n+1];p=new double[n+1];q=new double[n+1];y=new double[n+1];a[0]=0;e[0]=2*h[0];c[0]=h[0];for(i=1;i<n;i++){a[i]=h[i-1];e[i]=2*(h[i-1]+h[i]);c[i]=h[i];}a[n]=h[n-1];e[n]=2*h[n-1];c[n]=0;if(e[0]==0) cout<<"Method failed";else{p[0]=e[0];q[0]=c[0]/e[0];for(i=1;i<n;i++){p[i]=e[i]-a[i]*q[i-1];if(p[i]==0) {cout<<"Methgodfailed";break;}else q[i]=c[i]/p[i];}p[n]=e[n]-a[n]*q[n-1];if(p[n]==0) cout<<"Method failed";else{y[0]=d[0]/p[0];for(i=1;i<(n+1);i++)y[i]=(d[i]-a[i]*y[i-1])/p[i];t[n]=y[n];for(i=(n-1);i>=0;i--)t[i]=y[i]-q[i]*t[i+1];}}for(i=0;i<(n+1);i++){m[i]=6*t[i];cout<<"m["<<i<<"]="<<m[i]<<" ";}cout<<endl;A1=new double[n];A2=new double[n];A3=new double[n];A4=new double[n];for(i=0;i<n;i++){A1[i]=fx[i];A2[i]=b[i]-h[i]*(m[i+1]+2*m[i])/6;A3[i]=m[i]/2;A4[i]=(m[i+1]-m[i])/6*h[i];}for(i=0;i<n;i++)cout<<"A1["<<i<<"]="<<A1[i]<<" ";cout<<endl;for(i=0;i<n;i++)cout<<"A2["<<i<<"]="<<A2[i]<<" ";cout<<endl;for(i=0;i<n;i++)cout<<"A3["<<i<<"]="<<A3[i]<<" ";cout<<endl;for(i=0;i<n;i++)cout<<"A4["<<i<<"]="<<A4[i]<<" ";cout<<endl;cout<<"输入待测x个数:";int o;cin>>o;double *X;X=new double[o];for (i=0;i<o;i++){int k;cout<<"X["<<i<<"]=";cin>>X[i];k=s(n,x,X[i]);cout<<"f("<<X[i]<<")="<<(A1[k]+A2[k]*(X[i]-x[k])+A3[k]*(X[i]-x[k])*(X[i]-x[k])+A4[k]*(X[i]-x[k])*(X[i ]-x[k])*(X[i]-x[k]))<<endl;}deletea;deletec;deletee;deletep;deleteq;deletet;deletey;deletefx;deleteh;deletem;deleteb;deleted;dele te A1;delete A2;delete A3;delete A4;delete X;}样例输入待求阶数:3输入x:1 2 4 5输入fx:1 3 5 2输入dfa与dfb:1 -4m[0]=3.14286 m[1]=-0.285714 m[2]=-3.71429 m[3]=-1.14286 A1[0]=1 A1[1]=3 A1[2]=5A2[0]=1 A2[1]=2.42857 A2[2]=-1.57143A3[0]=1.57143 A3[1]=-0.142857 A3[2]=-1.85714A4[0]=-0.571429 A4[1]=-1.14286 A4[2]=0.428571输入待测x个数:2X[0]=1.5Sc(1.5)=S0(1.5)=1.82143X[1]=3Sc(3)=S1(3)=4.14286Press any key to continue。
三次样条插值(CubicSplineInterpolation)及代码实现(C语言)
三次样条插值(CubicSplineInterpolation)及代码实现(C语⾔)样条插值是⼀种⼯业设计中常⽤的、得到平滑曲线的⼀种插值⽅法,三次样条⼜是其中⽤的较为⼴泛的⼀种。
本篇介绍⼒求⽤容易理解的⽅式,介绍⼀下三次样条插值的原理,并附C语⾔的实现代码。
1. 三次样条曲线原理假设有以下节点1.1 定义样条曲线是⼀个分段定义的公式。
给定n+1个数据点,共有n个区间,三次样条⽅程满⾜以下条件:a. 在每个分段区间(i = 0, 1, …, n-1,x递增),都是⼀个三次多项式。
b. 满⾜(i = 0, 1, …, n )c. ,导数,⼆阶导数在[a, b]区间都是连续的,即曲线是光滑的。
所以n个三次多项式分段可以写作:,i = 0, 1, …, n-1其中ai, bi, ci, di代表4n个未知系数。
1.2 求解已知:a. n+1个数据点[xi, yi], i = 0, 1, …, nb. 每⼀分段都是三次多项式函数曲线c. 节点达到⼆阶连续d. 左右两端点处特性(⾃然边界,固定边界,⾮节点边界)根据定点,求出每段样条曲线⽅程中的系数,即可得到每段曲线的具体表达式。
插值和连续性:, 其中 i = 0, 1, …, n-1微分连续性:, 其中 i = 0, 1, …, n-2样条曲线的微分式:将步长带⼊样条曲线的条件:a. 由 (i = 0, 1, …, n-1)推出b. 由 (i = 0, 1, …, n-1)推出c. 由 (i = 0, 1, …, n-2)推出由此可得:d. 由 (i = 0, 1, …, n-2)推出设,则a. 可写为:,推出b. 将ci, di带⼊可得:c. 将bi, ci, di带⼊ (i = 0, 1, …, n-2)可得:端点条件由i的取值范围可知,共有n-1个公式,但却有n+1个未知量m 。
要想求解该⽅程组,还需另外两个式⼦。
所以需要对两端点x0和xn的微分加些限制。
三次样条插值法
三次样条插值法根据李庆阳的《数值分析》这本教材中的讲解编写的程序,使用的是第一边界条件,用追赶法求解了M矩阵。
为了调用方便,我将整个函数所有的信息构造成一个结构体,输入插值点的坐标和数量,定义边界条件后,将这个结构体的指针作为参数传给Spline3()函数,就完成了函数计算,计算结果也存储在该结构体中。
程序如下:/*=================================================================== ====*///=====================三次样条插值的函数S(x)实现=============================// 创建人:汪雅楠// 北京交通大学 QQ312818820// 说明:根据研究生教材《数值分析》(李庆杨)第51页~第56页编写/* 初始条件: 1. 已知两端的一阶导数值2. 已知两端的二阶导数值3. 周期样条函数### 此函数选择1条件 ###函数建立: 1. 设定样条函数S(x)的一阶导数为变量ki,用分段三次Hermitte差值2. 设定样条函数S(x)的二阶导数为变量Ki,用分段积分### 此函数选择2方法 ###矩阵求解:追赶法求解严格三对角占优矩阵{M},根据教材第195页编写*//*=================================================================== ====*/#include <stdio.h>///////////////////////////////////////////////////////////////////// ///////////#define MAXNUM 50 //定义样条数据区间个数最多为50个typedef struct SPLINE //定义样条结构体,用于存储一条样条的所有信息{ //初始化数据输入float x[MAXNUM+1]; //存储样条上的点的x坐标,最多51个点float y[MAXNUM+1]; //存储样条上的点的y坐标,最多51个点unsigned int point_num; //存储样条上的实际的点的个数float begin_k1; //开始点的一阶导数信息float end_k1; //终止点的一阶导数信息//float begin_k2; //开始点的二阶导数信息//float end_k2; //终止点的二阶导数信息//计算所得的样条函数S(x)float k1[MAXNUM+1]; //所有点的一阶导数信息float k2[MAXNUM+1]; //所有点的二阶导数信息//51个点之间有50个段,func[]存储每段的函数系数float a3[MAXNUM],a1[MAXNUM];float b3[MAXNUM],b1[MAXNUM];//分段函数的形式为Si(x) = a3[i] * {x(i+1) - x}^3 + a1[i] * {x(i+1) - x} +// b3[i] * {x - x(i)}^3 + b1[i] * {x - x(i)}//xi为x[i]的值,xi_1为x[i+1]的值}SPLINE,*pSPLINE;typedef int RESULT; //返回函数执行的结果状态,下面为具体的返回选项#ifndef TRUE#define TRUE 1#endif#ifndef FALSE#define FALSE -1#endif#ifndef NULL#define NULL 0#endif#ifndef ERR#define ERR -2#endif///////////////////////////////////////////////////////////////////// //////////////*=================================================================== ============*** 函数名称:Spline3()*** 功能说明:完成三次样条差值,其中使用追赶法求解M矩阵*** 入口参数:(pSPLINE)pLine 样条结构体指针pLine中的x[],y[],num,begin_k1,end_k1*** 出口参数:(pSPLINE)pLine 样条结构体指针pLine中的函数参数*** 返回参数:返回程序执行结果的状态TRUE or FALSE===================================================================== ===========*/RESULT Spline3(pSPLINE pLine){float H[MAXNUM] = {0}; //小区间的步长float Fi[MAXNUM] = {0}; //中间量float U[MAXNUM+1] = {0}; //中间量float A[MAXNUM+1] = {0}; //中间量float D[MAXNUM+1] = {0}; //中间量float M[MAXNUM+1] = {0}; //M矩阵float B[MAXNUM+1] = {0}; //追赶法中间量float Y[MAXNUM+1] = {0}; //追赶法中间变量int i = 0;////////////////////////////////////////计算中间参数if((pLine->point_num < 3) || (pLine->point_num > MAXNUM + 1)){return ERR; //输入数据点个数太少或太多}for(i = 0;i <= pLine->point_num - 2;i++){ //求H[i]H[i] = pLine->x[i+1] - pLine->x[i];Fi[i] = (pLine->y[i+1] - pLine->y[i]) / H[i]; //求F[x(i),x(i+1)] }for(i = 1;i <= pLine->point_num - 2;i++){ //求U[i]和A[i]和D[i]U[i] = H[i-1] / (H[i-1] + H[i]);A[i] = H[i] / (H[i-1] + H[i]);D[i] = 6 * (Fi[i] - Fi[i-1]) / (H[i-1] + H[i]);}//若边界条件为1号条件,则U[i] = 1;A[0] = 1;D[0] = 6 * (Fi[0] - pLine->begin_k1) / H[0];D[i] = 6 * (pLine->end_k1 - Fi[i-1]) / H[i-1];//若边界条件为2号条件,则//U[i] = 0;//A[0] = 0;//D[0] = 2 * begin_k2;//D[i] = 2 * end_k2;/////////////////////////////////////////追赶法求解M矩阵B[0] = A[0] / 2;for(i = 1;i <= pLine->point_num - 2;i++){B[i] = A[i] / (2 - U[i] * B[i-1]);}Y[0] = D[0] / 2;for(i = 1;i <= pLine->point_num - 1;i++){Y[i] = (D[i] - U[i] * Y[i-1]) / (2 - U[i] * B[i-1]);}M[pLine->point_num - 1] = Y[pLine->point_num - 1];for(i = pLine->point_num - 1;i > 0;i--){M[i-1] = Y[i-1] - B[i-1] * M[i];}//////////////////////////////////////////计算方程组最终结果for(i = 0;i <= pLine->point_num - 2;i++){pLine->a3[i] = M[i] / (6 * H[i]);pLine->a1[i] = (pLine->y[i] - M[i] * H[i] * H[i] / 6) / H[i];pLine->b3[i] = M[i+1] / (6 * H[i]);pLine->b1[i] = (pLine->y[i+1] - M[i+1] * H[i] * H[i] / 6) /H[i]; }return TRUE;}///////////////////////////////////////////////////////////////////// /////////////SPLINE line1;pSPLINE pLine1 = &line1;///////////////////////////////////////////////////////////////////// /////////////main(){line1.x[0] = 27.7;line1.x[1] = 28;line1.x[2] = 29;line1.x[3] = 30;line1.y[0] = 4.1;line1.y[1] = 4.3;line1.y[2] = 4.1;line1.y[3] = 3.0;line1.point_num = 4;line1.begin_k1 = 3.0;line1.end_k1 = -4.0;Spline3(pLine1);return 0;}///////////////////////////////////////////////////////////////////// /////////////。
三次样条插值c++代码实现及注释
一、引言在计算机编程和数据处理领域,插值是一种常见的数值分析方法,用于在已知数据点之间估算未知点的数值。
而三次样条插值是插值方法中的一种重要技术,它可以在使用较少插值节点的情况下,实现更为平滑和精确的插值结果。
本文将着重探讨三次样条插值的原理和C++代码实现,并给出详细的注释和解释。
二、三次样条插值的原理三次样条插值是一种分段插值方法,它将整个插值区间分割为若干个小区间,每个小区间内采用三次多项式进行插值。
这样做的好处是可以在每个小区间内实现更为细致和精确的插值,从而提高插值的准确性和平滑性。
而三次样条插值的核心在于确定每个小区间内的三次多项式的系数,一般采用自然边界条件进行求解。
在具体实现中,我们需要先对给定的插值节点进行排序,并求解出每个小区间内的三次多项式系数。
最终将这些系数整合起来,就可以得到整个插值区间的三次样条插值函数。
三、C++代码实现及注释接下来,我们将给出使用C++语言实现三次样条插值的代码,并对每个关键步骤进行详细注释和解释。
```cpp// include necessary libraries#include <iostream>#include <vector>using namespace std;// define the function for cubic spline interpolationvector<double> cubicSplineInterpolation(vector<double> x, vector<double> y) {// initialize necessary variables and containersint n = x.size();vector<double> h(n-1), alpha(n), l(n), mu(n), z(n), c(n), b(n), d(n);vector<double> interpolatedValues;// step 1: calculate the differences between x valuesfor (int i = 0; i < n-1; i++) {h[i] = x[i+1] - x[i];}// step 2: calculate alpha valuesfor (int i = 1; i < n-1; i++) {alpha[i] = (3/h[i]) * (y[i+1] - y[i]) - (3/h[i-1]) * (y[i] - y[i-1]); }// step 3: calculate l, mu, and z valuesl[0] = 1;mu[0] = 0;z[0] = 0;for (int i = 1; i < n-1; i++) {l[i] = 2*(x[i+1] - x[i-1]) - h[i-1]*mu[i-1];mu[i] = h[i]/l[i];z[i] = (alpha[i] - h[i-1]*z[i-1])/l[i];}l[n-1] = 1;z[n-1] = 0;c[n-1] = 0;// step 4: calculate coefficients for the cubic polynomials for (int j = n-2; j >= 0; j--) {c[j] = z[j] - mu[j]*c[j+1];b[j] = (y[j+1] - y[j])/h[j] - h[j]*(c[j+1] + 2*c[j])/3;d[j] = (c[j+1] - c[j])/(3*h[j]);}// step 5: interpolate values using the cubic polynomials for (int i = 0; i < n-1; i++) {double xi = x[i];while (xi < x[i+1]) {double dx = xi - x[i];double interpolatedValue = y[i] + b[i]*dx + c[i]*dx*dx + d[i]*dx*dx*dx;interpolatedValues.push_back(interpolatedValue);xi += 0.1; // adjust the step size for finer interpolation }}return interpolatedValues;}// main function for testing the cubic spline interpolation int main() {vector<double> x = {1, 2, 3, 4, 5};vector<double> y = {3, 6, 8, 10, 15};vector<double> interpolatedValues = cubicSplineInterpolation(x, y);for (int i = 0; i < interpolatedValues.size(); i++) {cout << "Interpolated value " << i << " : " << interpolatedValues[i] << endl;}return 0;}```四、总结与展望通过本文的学习,我们了解了三次样条插值的原理和C++代码实现。
C#三次样条插值函数(自然边界)
/****************函数说明*********************///pxpy为已知的数据点,xs为要插值的x坐标,最终会得到xs坐标下的y值using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace spline{class Program{staticvoid Main(string[] args){point[] points = new point[13];double[] px = { 64, 304, 544, 1035, 1502, 2061, 2540, 2939, 3498, 3897, 4456, 4696, 4936 }; double[]py={4.663,4.476,4.969,4.853,4.766,5.2415,4.795,4.7055,5.4565,5.5515,5.411,5.8385,6.7085} ;for (int i = 0; i< 13; i++){points[i] = new point();points[i].x =px[i];points[i].y = py[i];}point.DeSortX(points);double[] xs = {64, 304, 544, 1023, 1502, 1981, 2460, 2939, 3418, 3897, 4376, 4616, 4856}; splineInsertPoint(points, xs, 1);Console.ReadLine();}staticdouble[] splineInsertPoint(point[] points, double[] xs, int chf){int plength = points.Length;double[] h = newdouble[plength];double[] f = newdouble[plength];double[] l = newdouble[plength];double[] v = newdouble[plength];double[] g = newdouble[plength];//三转角法的待定一阶系数法。
4.4三次样条插值(共70张PPT)
解 做差商表(P111),由于是等距离(jùlí)节点,
hi xi xi1 0.15 i 1,2,3,4
i
hi hi1 hi
1 2
,
i
hi1 hi1 hi
1 2
第二十六页,共七十页。
由第二类边界条件得
2 1
M0 5.86667
0.5
2
0.5
M
1
5.14260
0.5
x1 6
] f
[
xi
1
,
xi
,
xi
1
]
(i 1,2,..., n 1)
M
n
1
2Mn
6
f [xn1, xn , xn ]
第二十二页,共七十页。
三次(sān cì)样条插值
第二类边界条件 s'' (x0 ) f '' (x0 ) M 0 , s'' (xn ) f '' (xn ) M n 同理可得
yi xi
yi1 xi1
2 (6 Mi
1 6 M i1)(xi
xi1)
(2)
因为s( x)连续,所以(1)(2)即
yi1 yi xi1 xi
(
1 6
M
i 1
2 6
M
i
)( xi 1
xi
)
yi xi
yi1 xi1
(
2 6
M
i
1 6
M
i 1
)( xi
xi1)
记hi xi xi1
i
hi hi1 hi
则法方程为其中xedx1008731273130873127313169030903平方误差为06277452对离散数据的曲线拟合最小二乘法曲线拟合问题对于fx插值问题要想提高精度就要增加节点因此多项式的次数也就太高计算量过大而节点少多项式的次数低但误差精度不能保证为了消除误差干扰取多一些节点利用最小二乘法确定低次多项式近似表示fx这就是曲线拟合问题
三次样条插值(Spline插值)
三次样条插值(Spline插值)当看到周围的同学抱怨样条的种种困难后,哥终于赶上⼤家的进度,开始写样条插值函数了。
基本情况:我们测试的函数以F(x)=1/(1+x^2)为例,检测样条函数S(x)在[-5,0]范围内的插值效果,样条S(x)满⾜S(xi)=yi,S'(x0)=F'(x0),S'(xn)=F'(xn),所以Spline插值将⽤到的数据有,(x0,y0)……(xn,yn)这n+1个点,以及F'(x0)与F'(xn)的值。
假定插值点x在xi~x(i+1)范围内,令h=x(i+1)-xi,t=(x-xi)/h:S(x)=f0(t)*yi+f1(t)*y(i+1)+g0(t)*h*mi+g1(t)*h*m(i+1),式中的mi=S'(xi)的值,并且由上可知,f0(x)=(2*x+1)*(x-1)^2,f1(x)=(-2*x+3)*x^2,g0(x)=x*(x-1)^2,g1(x)=(x-1)*x^2。
操作流程:从已知点中,求解mi的值,再对插值点寻找插值空间,代⼊进⾏插值。
实现过程:全程⽤float型,matrix[]⽤于存储数据点,M[]⽤于存储mi的值,解出mi的值要⽤到m[]、y[],分别⽤于存储线性⽅程组的系数与⽅程组的值。
1、数据点的产⽣//数据装载float x=-5;for(int i=0;i<row;i++){matrix[i*3]=x;matrix[i*3+1]=f(x);matrix[i*3+2]=g(x);x+=0.5;}2、线性⽅程组⽤于解mi//基本⽅程组⽣成器float a,b,h1,h2;for(int i=1;i<row-1;i++)//特别注意i值,以防数组越界{h1=matrix[(i+1)*3]-matrix[i*3];//h1表⽰h(i)h2=matrix[i*3]-matrix[(i-1)*3];//h2表⽰h(i-1)a=h2/(h1+h2);b=3*(1-a)*(matrix[i*3+1]-matrix[(i-1)*3+1])/h2+3*a*(matrix[(i+1)*3+1]-matrix[i*3+1])/h1;if(i>1&&i<row-2){i--;m[i*3]=1-a;m[i*3+1]=2;m[i*3+2]=a;y[i]=b;i++;}else if(i==1){m[0]=2;m[1]=a;m[2]=0;y[0]=b-(1-a)*matrix[2];}else if(i==row-2){i--;m[i*3]=0;m[i*3+1]=1-a;m[i*3+2]=2;y[i]=b-a*matrix[i*3+2];i++;}}3、根据产⽣的线性⽅程组的系数特点,⽤追赶法求解各点mi的值//⽤x[]存放mi的值,由于已经给F'(x0)与F'(xn),故m(0)与m(n)不必求解float *u=new float [row-1];//消元过程u[0]=m[1]/m[0];y[0]=y[0]/m[0];for(int i=1;i<row-1;i++)//u当中的i只有row-1个{u[i]=m[i*3+2]/(m[i*3+1]-u[i-1]*m[i*3]);y[i]=(y[i]-y[i-1]*m[i*3])/(m[i*3+1]-u[i-1]*m[i*3]);}y[i]=(y[i]-y[i-1]*m[i*3+1])/(m[i*3+2]-u[i-1]*m[i*3+1]);//对于最后⼀列,i*3+2与i*3+1意义有所不同//回代过程x[0]=matrix[2];x[row+1]=matrix[(row+1)*3+2];x[row]=y[i];for(i=row-2;i>=0;i--)x[i+1]=y[i]-u[i]*x[i+2];delete []u;4、样条插值float Spline(float x,float *matrix,float *M,int row){float tmp=0,h=0;for(int i=0;i<row;i++)if(x==matrix[i*3])return matrix[i*3+1];else if(matrix[i*3]<x&&x<matrix[(i+1)*3])break;cout<<"插值区间: [ "<<matrix[i*3]<<","<<matrix[(i+1)*3]<<" ]\n";h=matrix[(i+1)*3]-matrix[i*3];tmp=(x-matrix[i*3])/h;return f0(tmp)*matrix[i*3+1]+f1(tmp)*matrix[(i+1)*3+1]+h*g0(tmp)*M[i]+h*g1(tmp)*M[i+1];}总结:写样条其实不难,就是发现问题难;写程序其实也不难,就是调试难。
紧压三次样条插值程序讲解
求压紧三次样条函数的函数程序function S=liti05_7(X,Y,dx0,dxn)%Input -X is the 1xn abscissa vector% -Y is the 1xn ordinate vector% -dx0=S'(x0) first derivative boundary condition% -dxn=S'(xn) first derivative boundary condition%Output -S:rows of S are the confficients,indescending order,for the cubic interplantsN=length(X)-1; %求当前问题的规模数--x的最大下标H=diff(X); %求X的差分 h0 h1…… h n-1D=diff(Y)./H; %求 y 对 x 的一阶差商 d0 d1…… d n-1A=H(2:N-1); %为求线性方程组系数矩阵上次对角元做准备B=2*(H(1:N-1)+H(2:N)); %求线性方程组系数矩阵主对角元做准备C=H(2:N-1); %求线性方程组系数矩阵上次对角元U=6*diff(D); %为求线性方程组常数列向量做准备%压紧样条端点约束B(1)=B(1)-H(1)/2; %3h0/2+2h1U(1)=U(1)-3*(D(1)-dx0); %修改 u(1)B(N-1)=B(N-1)-H(N)/2; % 2h(N-2)+3*h(N-1)/2U(N-1)=U(N-1)-3*(dxn-D(N)); %修改 u(N-1)A %输出线性方程组系数矩阵上次对角元向量B %输出线性方程组系数矩阵主对角元向量C %输出线性方程组系数矩阵下次对角元向量U %输出线性方程组常数列向量% 下面开始解三对角线行方程组% 首先转化为上三角线性方程组for k=2:N-1temp=A(k-1)/B(k-1);B(k)=B(k)-temp*C(k-1);U(k)=U(k)-temp*U(k-1);end%回代求解M(N)=U(N-1)/B(N-1);for k=N-2:-1:1M(k+1)=(U(k)-C(k)*M(k+2))/B(k);end%计算端点x0 x n上的二阶导数M(1)=3*(D(1)-dx0)/H(1)-M(2)/2;M(N+1)=3*(dxn-D(N))/H(N)-M(N)/2;M % 输出各节点上的二阶导数for k=0:N-1%计算第k个多项式的系数S(k+1,1)=(M(k+2)-M(k+1))/(6*H(k+1)); %算(x-X(k))三次项系数S(k+1,2)=M(k+1)/2; %算(x-X(k))二次项系数S(k+1,3)=D(k+1)-H(k+1)*(2*M(k+1)+M(k+2))/6;%算(x-X(k))一次项系数S(k+1,4)=Y(k+1); %算(x- X(k))零次项系数endhold onplot(X,Y,'kO') % 画样点style=['r', 'g', 'b']; % 由于例题中N等于3,style只构造了三个元素for k=1:N%画第k个区间上的三次函数曲线段x1=X(k):0.01:X(k+1);y1=polyval(S(k,:),x1-X(k)); %算关于(x- X(k))三次多项式的值plot(x1,y1,style(k))endgrid onxlabel('x');ylabel('y');hold off例求压紧三次样条曲线,经过点(0,0),(1,0.5),(2,2.0),(3,1.5),一阶导数的边界条件为S’(0)=0.2和S’(3)=-1针对上例,程序运行结果如下?x=[0 1 2 3];y=[0 0.5 2.0 1.5];?dx0=0.2;dxn=-1;?s=liti05_7(x,y,dx0,dxn)A =1B =3.5000 3.5000C =1U =5.1000 -10.5000M =-0.3600 2.5200 -3.7200 0.3600s =0.4800 -0.1800 0.2000 0-1.0400 1.2600 1.2800 0.50000.6800 -1.8600 0.6800 2.0000yx。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
三次样条插值C/C++程序(自己整理的)具体推导看书<<数值分析>>code:#include <iostream>using namespace std;const int MAXN = 100;int n;double x[MAXN], y[MAXN]; //下标从0..ndouble alph[MAXN], beta[MAXN], a[MAXN], b[MAXN];double h[MAXN];double m[MAXN]; //各点的一阶导数;inline double sqr(double pa) {return pa * pa;}double sunc(double p, int i) {return (1 + 2 * (p - x[i]) / (x[i + 1] - x[i])) * sqr((p - x[i + 1]) / (x[i + 1] - x[i])) * y[i] + (1 + 2 * (p - x[i + 1]) / (x[i] - x[i + 1])) * sqr((p - x[i]) / (x[i + 1] - x[i])) * y[i + 1] + (p - x[i]) * sqr((p - x[i + 1]) / (x[i] - x[i + 1])) * m[i]+ (p - x[i + 1]) * sqr((p - x[i]) / (x[i + 1] - x[i])) * m[i + 1];}int main() {int i, j;freopen("threeInsert.in", "r", stdin);scanf("%d", &n);for (i = 0; i <= n; i++) scanf("%lf%lf", &x[i], &y[i]);// scanf("%lf%lf", &m[0], &m[n]);for (i = 0; i <= n - 1; i++) h[i] = x[i + 1] - x[i];//第一种边界条件//alph[0] = 0; alph[n] = 1; beta[0] = 2 * m[0]; beta[n] = 2 * m[n];//第二种边界条件alph[0] = 1; alph[n] = 0; beta[0] = 3 * (y[1] - y[0]) / h[0]; beta[n] = 3 * (y[n] - y[n - 1] / h[n - 1]);for (i = 1; i <= n - 1; i++) {alph[i] = h[i - 1] / (h[i - 1] + h[i]);beta[i] = 3 * ((1 - alph[i]) * (y[i] - y[i - 1]) / h[i - 1] + alph[i] * (y[i + 1] - y[i]) / h[i]);}a[0] = - alph[0] / 2; b[0] = beta[0] / 2;for (i = 1; i <= n; i++) {a[i] = - alph[i] / (2 + (1 - alph[i]) * a[i - 1]);b[i] = (beta[i] - (1 - alph[i]) * b[i - 1]) / (2 + (1 - alph[i]) * a[i - 1]);}m[n + 1] = 0;for (i = n; i >= 0; i--) {m[i] = a[i] * m[i + 1] + b[i];}scanf("%lf", &xx);for (i = 0; i < n; i++) {if (xx >= x[i] && xx <= x[i + 1]) break;}printf("%lf\n", sunc(xx, i));}#include<iostream>#include<iomanip>using namespace std;const int MAX = 50;float x[MAX], y[MAX], h[MAX];//变量设置:x为各点横坐标;y为各点纵坐标;h为步长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<<"请输入已知断点个数:";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++) //求步长;其数组值较之x,y个数少一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";//显示数据为Y0'至Yn',即断点的一阶导数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";//显示数据为Y0"至Yn",即断点的二阶导数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);//调用差分函数(only!) 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);//调用弯矩函数(only!)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);//通过操作器setprecision()设置有效位数;其为头文件<iomanip.h>所包含;括号内为参数。
for(int i = 0; i < n; i++)//所输出函数个数由所设断点个数而定{cout<<i+1<<": ["<<x[i]<<" , "<<x[i+1]<<"]\n"<<"\t";float t = fxym[i]/(6*h[i]);if(t > 0)cout<<t<<"*("<<x[i+1]<<" - x)^3";elsecout<<-t<<"*(x - "<<x[i+1]<<")^3";t = fxym[i+1]/(6*h[i]);if(t > 0)cout<<" + "<<t<<"*(x - "<<x[i]<<")^3";elsecout<<" - "<<-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)";elsecout<<"- "<<-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]<<")";elsecout<<" - "<<-t<<"*(x - "<<x[i]<<")";cout<<endl<<endl;}cout<<endl;}/****************提供测试数据:(来自课本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)*////////////////////////////////////////////////////// purpose:给定,值的三次样条插值多项式/////////////////////////////////////////////////////# define MAX_N 20 // 定义(x_i,y_i)的最大的维数typedef struct tagPOINT // 点的结构{double x;double y;} POINT;int main ( ){int n;int i,k;POINT points[MAX_N +1];double h[MAX_N +1],b[MAX_N +1],c[MAX_N +1],d[MAX_N +1],M[MAX_N +1]; double u[MAX_N +1],v[MAX_N +1],y[MAX_N +1];double x,p,q,S;printf ("\nInput n value:"); // 输入插值点的数目scanf ("%d",&n);if (n>MAX_N){printf ("The input n is larger than MAX_N, please redefine the MAX_N. \n"); return 1;}if (n<=0){printf ("Please input a number between 1 and % d. \n",MAX_N);return 1;}// 输入插值点(x_i,y_i),M0值和Mn值printf ("Now input the (x_i,y_i),i=0,…,% d:\n",n);for (i=0;i<n;i++){scanf ("%lf %lf",&points[i].x,&points[i].y);printf("%lf %lf\n",points[i].x,points[i].y);}printf ("Now input the M[0] value:");scanf ("%lf",&M[0]);printf ("\nNow input the M[n] value:");scanf ("%lf",&M[n]);printf ("\nNow input the x value:");//输入计算三次样条插值函数的x值scanf ("%lf",&x);if (x>points[n-1]. x || x<points[0].x){printf ("Please input a number between %f and %f. \n",points[0].x,points[n].x); return 1;}// 计算M关系式中各参数的值h[0]=points[1].x-points[0].x;for (i=1;i<n;i++ ){h[i]=points[i+1].x-points[i].x;b[i]=h[i]/(h[i]+h[i-1]);c[i]=1-b[i];d[i]=6*((points[i+1].y-points[i].y)/h[i]-(points[i].y-points[i-1].y)/h[i-1])/(h[i]+h[i-1]);}// 用追赶法计算Mi,i=1,…,n-1d[1]-= c[1]*M[0];d[n-1]-=b[n-1]*M[n];b[n-1]=0;c[1]=0;v[0]=0;for ( i=1;i<n;i++){u[i]=2-c[i]*v[i-1];v[i]=b[i]/u[i];y[i]= (d[i]-c[i]*y[i-1])/u[i];}for (i=1;i<n;i++){M[n-i]=y[n-i]-v[n-i]* M[n-i+1];}// 计算三次样条插值函数在x处的值k=0;while (x>= points[k].x) k++;k=k-1;p=points[k+1].x-x;q=x-points[k].x;S=(p* p* p* M[k] +q* q* q* M[k+1]) / (6* h[k])+( p* points [k].y+q* points[k+1].y) / h[k]-h[k]*(p* M[k] +q* M[k]+q* M[k+1])/6; printf ("S(%f ) = %f\n",x,S);// 输出getchar ( );return 0;}#include"iostream.h"#include"fstream.h"#define N 100float X[N],Y[N],M[N],a,b;double f(int i,int j){double sum1=0;if(j-i==1) return (Y[j]-Y[i])/(X[j]-X[i]);else return (f(i+1,j)-f(i,j-1))/(X[j]-X[i]);}void main(){ifstream istrm("E:\\data.txt");//这里是文件的输入,请相应改成普通键盘输入int n=3;for(int i=0;i<=n;i++)istrm>>X[i]>>Y[i];istrm>>a>>b;float h[N],u[N],q[N],d[N];for(i=0;i<n;i++)h[i]=X[i+1]-X[i];q[0]=1;q[n]=0;for(i=1;i<n;i++)q[i]=h[i]/(h[i-1]+h[i]);for(i=0;i<=n;i++)u[i]=1-q[i];d[0]=(6*(f(0,1)-a))/h[0];d[n]=(6*(b-f(n-1,n)))/h[n-1];for(i=1;i<n;i++)d[i]=6*f(i-1,i+1);float m[N];for(i=0;i<=n;i++) m[i]=2;for(i=1;i<=n;i++){m[i]=m[i]-(u[i]/m[i-1])*q[i-1]; d[i]=d[i]-(u[i]/m[i-1])*d[i-1];}M[n]=d[n]/m[n];cout<<M[n]<<endl;for(i=n-1;i>=0;i--){M[i]=(d[i]-q[i]*M[i+1])/m[i]; cout<<M[i]<<endl;}}。