数值分析插值算法源程序
- 格式:doc
- 大小:62.50 KB
- 文档页数:7
数值分析插值法插值法是数值分析中的一种方法,用于通过已知数据点的函数值来估计介于这些数据点之间的未知函数值。
插值法在科学计算、数据处理、图像处理等领域中得到广泛应用。
插值法的基本思想是通过已知数据点构造一个函数,使得该函数逼近未知函数,并在已知数据点处与未知函数值相等。
插值法的关键是选择适当的插值函数,以保证估计值在插值区间内具有良好的近似性质。
常用的插值法有拉格朗日插值法、牛顿插值法和埃尔米特插值法等。
以下将分别介绍这些插值法的原理及步骤:1. 拉格朗日插值法:拉格朗日插值法通过构造一个多项式函数来逼近未知函数。
假设已知n+1个数据点(x0, y0), (x1, y1), ..., (xn, yn),其中x0, x1, ..., xn为给定的节点,y0, y1, ..., yn为对应的函数值。
拉格朗日插值多项式的一般形式为:L(x) = y0 * l0(x) + y1 * l1(x) + ... + yn * ln(x)其中l0(x), l1(x), ..., ln(x)为拉格朗日基函数,定义为:li(x) = (x - x0)(x - x1)...(x - xi-1)(x - xi+1)...(x - xn) / (xi - x0)(xi - x1)...(xi - xi-1)(xi - xi+1)...(xi - xn)拉格朗日插值法的步骤为:a. 计算基函数li(xi)的值。
b.构造插值多项式L(x)。
c.计算L(x)在需要估计的插值点上的函数值f(x)。
2.牛顿插值法:牛顿插值法通过构造一个差商表来逼近未知函数。
差商表的第一列为已知数据点的函数值,第二列为相邻数据点的差商,第三列为相邻差商的差商,以此类推。
最终,根据差商表中的数值,构造一个差商表与未知函数值相等的多项式函数。
牛顿插值法的步骤为:a.计算差商表的第一列。
b.计算差商表的其他列,直至最后一列。
c.根据差商表构造插值多项式N(x)。
数值分析第五章插值法插值法是数值分析中常用的一种数值逼近方法,它的目的是通过已知数据点之间的插值多项式来逼近未知数据点的函数值。
插值法可以在信号处理、图像处理、计算机图形学等领域中广泛应用。
在插值法中,最常用的方法有拉格朗日插值法和牛顿插值法。
拉格朗日插值法是一种利用拉格朗日插值多项式来逼近函数的方法。
对于n个已知数据点(xi, yi),拉格朗日插值多项式L(x)可以表示为:L(x) = ∑(yi * li(x))其中,li(x)表示拉格朗日基函数,定义为:li(x) = ∏[(x - xj)/(xi - xj)] (j≠i)可以证明,在给定的n个数据点上,拉格朗日插值多项式L(x)满足:L(xi) = yi牛顿插值法是另一种常用的插值方法,它利用差商的概念来逼近函数。
对于n个已知数据点(xi, yi),差商可以定义为:f[xi] = yif[xi, xi+1] = (f[xi+1] - f[xi]) / (xi+1 - xi)f[xi, xi+1, ..., xi+k] = (f[xi+1, ..., xi+k] - f[xi, ...,xi+k-1]) / (xi+k - xi)通过差商的递归定义,可以得到牛顿插值多项式N(x)的表达式,其中:N(x)=f[x0]+f[x0,x1](x-x0)+f[x0,x1,x2](x-x0)(x-x1)+...与拉格朗日插值法类似,牛顿插值多项式N(x)也满足:N(xi) = yi这两种插值方法都有自己的优点和缺点。
拉格朗日插值法简单易懂,计算量小,但当数据点较多时,多项式的次数会很高,容易出现龙格现象。
而牛顿插值法可以通过求差商一次次递推得到插值多项式,计算效率较高,且具备局部逼近性,不易出现龙格现象。
除了拉格朗日插值法和牛顿插值法,还有其他插值方法,如分段线性插值、样条插值等。
分段线性插值是利用线性多项式逼近函数,将数据点之间的区间分为若干段,每段内使用一条线性多项式进行插值。
1 / 21数值分析实验二:插值法1 多项式插值的震荡现象1.1 问题描述考虑一个固定的区间上用插值逼近一个函数。
显然拉格朗日插值中使用的节点越多,插值多项式的次数就越高。
我们自然关心插值多项式的次数增加时, 是否也更加靠近被逼近的函数。
龙格(Runge )给出一个例子是极著名并富有启发性的。
设区间[-1,1]上函数21()125f x x=+ (1)考虑区间[-1,1]的一个等距划分,分点为n i nix i ,,2,1,0,21 =+-= 则拉格朗日插值多项式为201()()125nn ii iL x l x x ==+∑(2)其中的(),0,1,2,,i l x i n =是n 次拉格朗日插值基函数。
实验要求:(1) 选择不断增大的分点数目n=2, 3 …. ,画出原函数f(x)及插值多项式函数()n L x 在[-1,1]上的图像,比较并分析实验结果。
(2) 选择其他的函数,例如定义在区间[-5,5]上的函数x x g xxx h arctan )(,1)(4=+=重复上述的实验看其结果如何。
(3) 区间[a,b]上切比雪夫点的定义为 (21)cos ,1,2,,1222(1)k b a b ak x k n n π⎛⎫+--=+=+ ⎪+⎝⎭(3)以121,,n x x x +为插值节点构造上述各函数的拉格朗日插值多项式,比较其结果,试分析2 / 21原因。
1.2 算法设计使用Matlab 函数进行实验, 在理解了插值法的基础上,根据拉格朗日插值多项式编写Matlab 脚本,其中把拉格朗日插值部分单独编写为f_lagrange.m 函数,方便调用。
1.3 实验结果1.3.1 f(x)在[-1,1]上的拉格朗日插值函数依次取n=2、3、4、5、6、7、10、15、20,画出原函数和拉格朗日插值函数的图像,如图1所示。
Matlab 脚本文件为Experiment2_1_1fx.m 。
可以看出,当n 较小时,拉格朗日多项式插值的函数图像随着次数n 的增加而更加接近于f(x),即插值效果越来越好。
实验一:拉格朗日插值多项式命名(源程序.cpp及工作区.dsw):lagrange问题:4//Lagrange.cpp#include <stdio.h>#include <conio.h>#define N 4int checkvalid(double x[], int n);void printLag (double x[], double y[], double varx, int n);double Lagrange(double x[], double y[], double varx, int n);void main (){double x[N+1] = {0.4, 0.55, 0.8, 0.9, 1};double y[N+1] = {0.41075, 0.57815, 0.88811, 1.02652, 1.17520};double varx = 0.5;if (checkvalid(x, N) == 1){printf("\n\n插值结果: P(%f)=%f\n", varx, Lagrange(x, y, varx, N));}else{printf("结点必须互异");}getch();}int checkvalid (double x[], int n){int i,j;for (i = 0; i < n; i++){for (j = i + 1; j < n+1; j++){if (x[i] == x[j])//若出现两个相同的结点,返回-1{return -1;}}}return 1;}double Lagrange (double x[], double y[], double varx, int n) {double fenmu;double fenzi;double result = 0;int i,j;printf("Ln(x) =\n");for (i = 0; i < n+1; i++){fenmu = 1;for (j = 0; j < n+1; j++){if (i != j){fenmu = fenmu * (x[i] - x[j]);}}printf("\t%f", y[i] / fenmu);fenzi = 1;for (j = 0; j < n+1; j++){if (i != j){printf("*(x-%f)", x[j]);fenzi = fenzi * (varx - x[j]);}}if (i != n){printf("+\n");}result += y[i] / fenmu * fenzi;}return result;}运行及结果显示:实验二:牛顿插值多项式命名(源程序.cpp及工作区.dsw):newton_cz问题:4//newton_cz.cpp#include<stdio.h>#include<iostream.h>#include<conio.h>#define N 4int checkvaild(double x[],int n){int i,j;for(i=0;i<n+1;i++){for(j=i+1;j<n+1;j++)if(x[i]==x[j])return -1;}return 1;}void chashang(double x[],double y[],double f[][N+1]){int i,j,t=0;for(i=0;i<N+1;i++){f[i][0]=y[i];//f[0][0]=y[0],f[1][0]=y[1];f[2][0]=y[2];f[3][0]=y[3];f[4][0]=y[4] }for(j=1;j<N+1;j++)// 阶数j{for(i=0;i<N-j+1;i++) //差商个数if[i][j]=(f[i+1][j-1]-f[i][j-1])/(x[t+i+1]-x[i]);//一阶为f[0][1]~f[3][1];二阶为f[0][2]~f[2][2]//三阶为f[0][3]~f[1][3];四阶为f[0][4]t++;}}double compvalue(double t[][N+1],double x[],double varx){int i,j,r=0;double sum=t[0][0],m[N+1]={sum,1,1,1,1};printf("i\tXi\t F(Xi)\t 1阶\t 2阶\t\t3阶\t 4阶\n");printf("--------------------------------------------------------------------------------");for(i=0;i<N+1;i++){r=i;printf("x%d\t%f ",i,x[i]);for(j=0;j<=i;j++){printf("%f ",t[r][j]);r--;}printf("\n");}printf("--------------------------------------------------------------------------------");/**/ printf("N(x) =\n");printf(" %f\n",t[0][0]);for(i=1;i<N+1;i++){for(j=0;j<i;j++)m[i]=m[i]*(varx-x[j]);m[i]=t[0][i]*m[i];sum=sum+m[i];}for(i=1;i<N+1;i++){ printf(" +%f*",t[0][i]);for(j=0;j<i;j++)printf("(x-%f)",x[j]);printf("\n");}return sum;}void main(){double varx,f[N+1][N+1];double x[N+1]={0.4,0.55,0.8,0.9,1};double y[N+1]={0.41075,0.57815,0.88811,1.02652,1.17520};checkvaild(x,N);chashang(x,y,f);varx=0.5;if(checkvaild(x,N)==1){chashang(x,y,f);printf("\n\n牛顿插值结果: P(%f)=%f\n",varx,compvalue(f,x,varx));}elseprintf("输入的插值节点的x值必须互异!");getch();} 运行及结果显示:实验三:自适应梯形公式命名(源程序.cpp 及工作区.dsw ):autotrap ][n T问题:计算⎰+=10214dx x π的近似值,使得误差(EPS )不超过610- //autotrap.cpp #include<stdio.h> #include<conio.h> #include<math.h> #define EPS 1e-6 double f(double x) { return 4/(1+x*x); } double AutoTrap(double(*f)(double),double a,double b,double eps) { double t2,t1,sum=0.0; int i,k; t1=(b-a)*(f(a)+f(b))/2; printf("T(%4d)=%f\n",1,t1); for(k=1;k<11;k++) { for(i=1;i<=pow(2,k-1);i++) sum+=f(a+(2*i-1)*(b-a)/pow(2,k)); t2=t1/2+(b-a)*sum/pow(2,k); printf("T(%4d)=%f\n",(int)pow(2,k),t2); if(fabs(t2-t1)<EPS) break; else t1=t2; sum=0.0; } return sum; } void main(){ double s;s=AutoTrap(f,0.0,1.0,EPS);getch();} 运行及结果显示:实验四:龙贝格算法命名(源程序.cpp 及工作区.dsw ):romberg问题:求⎰+=10214dx x π的近似值,要求误差不超过610-//romberg.cpp #include <stdio.h> #include <conio.h> #include <math.h> #define N 20 #define EPS 1e-6 double f(double x){return 4/(1+x*x);} double Romberg(double a,double b,double (*f)(double),double eps) { double T[N][N],p,h;int k=1,i,j,m=0;T[0][0]=(b-a)/2*(f(a)+f(b));do{p=0;h=(b-a)/pow(2,k-1);for(i=1;i<=pow(2,k-1);i++)p=p+f(a+(2*i-1)*h/2);T[0][k]=T[0][k-1]/2+p*h/2;for(i=1;i<=k;i++){j=k-i;T[i][j]=(pow(4,i)*T[i-1][j+1]-T[i-1][j])/(pow(4,i)-1); }k++; p=fabs(T[k-1][0]-T[k-2][0]);}while(p>=EPS);k--; while(m<=k){for(i=0;i<=m;i++) printf("T(%d,%d)=%f ",i,m-i,T[i][m-i]);m++;printf("\n");}return T[k][0]; } void main() {printf("\n\n 积分结果 = %f",Romberg(0,1,f,EPS)); getch(); } 运行及结果显示:实验五:牛顿切线法问题:求方程01)(3=--=x x x f 在5.1=x ,6.0=x 附近的根(精度31021-⨯=) //newton_qxf.cpp#include <math.h>#include<conio.h>#include <stdio.h>#define MaxK 1000#define EPS 0.5e-3double f(double x){return x*x*x-x-1;}double f1(double x){return 3*x*x-1;}int newton(double (*f)(double), double (*f1)(double), double &x0, double eps) {double xk, xk1;int count = 0;printf("k\txk\n");printf("-----------------------\n");xk = x0;printf("%d\t%f\n", count, xk);do{if((*f1)(xk)==0)return 2;xk1 = xk - (*f)(xk) / (*f1)(xk);if (fabs(xk - xk1) < eps){count++;xk = xk1;printf("%d\t%f\n", count, xk);x0 = xk1;return 1;}count++;xk = xk1;printf("%d\t%f\n", count, xk);}while(count < MaxK);return 0;}void main(){for(int i=0;i<2;i++){double x=0.6;if(i==1)x=1.5;printf("x0初值为%f:\n",x);if (newton(f, f1, x, EPS) == 1){printf("-----------------------\n");printf("the root is x=%f\n\n\n", x);}else{printf("the method is fail!");}}getch();}实验六:牛顿下山法命名(源程序.cpp 及工作区.dsw ):newton_downhill 问题:求方程01)(3=--=x x x f 在5.1=x ,6.0=x 附近的根(精度31021-⨯=) //newton_downhill.cpp #include <stdio.h> #include <conio.h> #include <math.h> #include <stdlib.h> #define Et 1e-3//下山因子下界 #define E1 1e-3//根的误差限 #define E2 1e-3//残量精度 double f(double x) { return x * x * x - x - 1; } double f1(double x) { return 3 * x * x - 1; } void errormess(int b){char *mess;switch(b){case -1:mess = "f(x)的导数为0!";break;case -2:mess = "下山因子已越界,下山处理失败";break;default:mess = "其他类型错误!";}printf("the method has faild! because %s", mess);}int Newton(double (*f)(double), double (*f1)(double), double &x0) {int k = 0;double t;double xk, xk1;double fxk, fxk_temp;printf("k t xk f(xk)\n");printf("----------------------------------------------------------\n");printf("%-20d", k);xk = x0;printf("%-15f", x0);fxk = (*f)(xk);printf("%-20f", fxk);printf("\n");for (k = 1; ; k++){t = 1;while(1){printf("%-10d", k);printf("%-10f", t);if((*f1)(xk) != 0){xk1 = xk - t * (*f)(xk) / (*f1)(xk);}else{return -1;}printf("%-15f", xk1);fxk_temp = (*f)(xk1);printf("%-20f", fxk_temp);if(fabs(fxk_temp) >fabs(fxk)){t = t / 2;printf("\n");if (t < Et){return -2;}}else{printf("下山成功\n");break;}}if (fabs(xk-xk1)<E1){x0 = xk1;return 1; } xk = xk1; } }void main() {int b;double x0; x0 = 0.6;b = Newton(f, f1, x0); if (b == 1) printf("\nthe root x=%f\n", x0); else errormess(b); getch(); }运行及结果显示:实验七:埃特金加速算法命名(源程序.cpp 及工作区.dsw ):aitken问题:求方程01)(3=--=x x x f 在5.1=x ,6.0=x 附近的根(精度31021-⨯=) //aitken.cpp#include <math.h> #include <stdio.h> #include <conio.h> #define MaxK 100 #define EPS 0.5e-3double g(double x) {return x * x * x - 1; }int aitken (double (*g)(double), double &x, double eps) {int k;double xk = x, yk, zk, xk1;printf("k xk yk zk xk+1\n");printf("-------------------------------------------------------------------\n"); for (k = 0;k<MaxK; k++) { yk = (*g)(xk); zk = (*g)(yk);xk1 = xk - (yk - xk) * (yk - xk) / (zk - 2 * yk + xk); printf("%-10d%-15f%-15f%-15f%-15f\n", k, xk, yk, zk, xk1); if (fabs(yk-xk)<=eps) { x = xk1; return k + 1; } xk = xk1; }return -1; }void main () {double x = 1.5; int k;k = aitken(g, x, EPS); if (k == -1) printf("迭代次数越界!\n"); else printf("\n 经k=%d 次迭代,所得方程根为:x=%f\n", k, x); getch(); }运行及结果显示:实验八:正割法问题:求方程01)(3=--=x x x f 在5.1=x 附近的根(精度0.5e-8) //ZhengGe.cpp #include <math.h> #include <stdio.h> #include <conio.h>#define MaxK 1000 #define EPS 0.5e-8double f(double x) {return x*x*x-x-1;}int ZhengGe(double (*f)(double), double x0, double &x1, double eps) {printf("k xk f(xk)\n");printf("---------------------------------------------\n");int k;double xk0, xk, xk1;xk0 = x0;printf("%-10d%-15f%-15f\n", 0, x0, (*f)(x0));xk = x1;for (k=1;k<MaxK;k++){if((*f)(xk)-(*f)(xk0)==0)return -1;xk1 = xk - (*f)(xk) / ( (*f)(xk) - (*f)(xk0) ) * (xk - xk0);printf("%-10d%-15f%-15f\n", k, xk, (*f)(xk));if (fabs(xk1 - xk)<=eps){printf("%-10d%-15f%-15f\n\n", k + 1, xk1, (*f)(xk1));printf("---------------------------------------------\n\n");x1 = xk1;return 1;}xk0 = xk;xk = xk1;}return -2;}void main (){double x0 = 1, x1 = 2;if (ZhengGe(f, x0, x1, EPS) == 1){printf("the root is x = %f\n", x1);}else{printf("the method is fail!");}getch();}实验九:高斯列选主元算法命名(源程序.cpp 及工作区.dsw ):colpivot问题:求解方程组并计算系数矩阵行列式值 ⎪⎩⎪⎨⎧=-+=+-=-+2240532321321321x x x x x x x x x//colpivot.cpp#include <math.h> #include <stdio.h> #include <conio.h> #define N 3static double aa[N][N]={{1,2,-1},{1,-1,5},{4,1,-2}}; static double bb[N+1]={3,0,2};void main() {int i,j;double a[N+1][N+1],b[N+1],x[N+1],det;double gaussl(double a[][N+1],double b[],double x[]); for(i=1;i<=N;i++) { for(j=1;j<=N;j++) a[i][j]=aa[i-1][j-1]; b[i]=bb[i-1]; }det=gaussl(a,b,x); if(det!=0) { printf("\n 方程组的解为:"); for(i=1;i<=N;i++) printf(" x[%d]=%f",i,x[i]); printf("\n\n 系数矩阵的行列式值=%f",det); }else printf("\n\n 系数矩阵奇异阵,高斯方法失败 !:"); getch(); }double gaussl(double a[][N+1],double b[],double x[])//a传入增广矩阵(有效元素为a[1,1]...a[n,n+1]),x负责传入迭代初值并返回解向量//(有效值为x[1]...x[n]);返回值:系数矩阵行列式值detA{double det=1.0,F,m,temp;int i,j,k,r;void disp(double a[][N+1],double b[]);printf("消元前增广矩阵:\n");disp(a,b);for(k=1;k<N;k++){temp=a[k][k];r=k;for(i=k+1;i<=N;i++){if(fabs(temp)<fabs(a[i][k])){temp=a[i][k];r=i;}//按列选主元,即确定ik}if(a[r][k]==0)return 0;//如果aik,k=0,则A为奇异矩阵,停止计算if(r!=k){for(j=k;j<=N;j++){a[k][j]+=a[r][j];a[r][j]=a[k][j]-a[r][j];a[k][j]-=a[r][j];}b[k]+=b[r];b[r]=b[k]-b[r];b[k]-=b[r];det=-det;//如果ik!=k,则交换[A,b]第ik行与第k行元素printf("交换第%d, %d行:\n",k,r);disp(a,b);}for(i=k+1;i<=N;i++){m=a[i][k]/a[k][k];for(j=1;j<=k;j++)a[i][j]=0.0;for(j=k+1;j<=N;j++)a[i][j]-=m*a[k][j];b[i]-=m*b[k];}printf("第%d次消元:\n",k);disp(a,b);det*=a[k][k];} //大FOR循环结束x[N]=b[N]/a[N][N];for(i=N-1;i>0;i--){F=0.0;for(j=i+1;j<=N;j++)F+=a[i][j]*x[j];x[i]=(b[i]-F)/a[i][i];}det*=a[N][N];return det;}void disp(double a[][N+1],double b[])//显示选主元及消元运算中间增广矩阵结果 {int i,j;for(i=1;i<=N;i++) {for(j=1;j<=N;j++)printf("%10f\t",a[i][j]); printf("%10f\n",b[i]); } }运行及结果显示:实验十:高斯全主元消去算法 命名(源程序.cpp 及工作区.dsw ):fullpivot问题:利用全主元消去法求解方程组⎥⎥⎥⎦⎤⎢⎢⎢⎣⎡-=⎥⎥⎥⎦⎤⎢⎢⎢⎣⎡⎥⎥⎥⎦⎤⎢⎢⎢⎣⎡----9555.04525.015.0201.0321x x x //fullpivot.cpp#include <math.h> #include <stdio.h> #include <conio.h> #define N 3 double x[N+1];static double aa[N][N]={{0.01,2,-0.5},{-1,-0.5,2},{5,-4,0.5}}; static double bb[N]={-5,5,9};void main(){int i,j;double a[N+1][N+1],b[N+1],x[N+1],det;int t[N+1];//引入列交换保存x向量的各分量的位置顺序double gaussl(double a[][N+1],double b[],double x[],int t[]);for(i=1;i<=N;i++){for(j=1;j<=N;j++) a[i][j]=aa[i-1][j-1];b[i]=bb[i-1];}for(i=1;i<=N;i++)t[i]=i;det=gaussl(a,b,x,t);if(det!=0){ printf("\n方程组的解为:");for(i=N;i>=1;i--){printf(" x[%d]=%f",t[i],x[i]);if(i>1)printf(" -->");}printf("\n\n系数矩阵的行列式值=%f",det);}else printf("\n\n系数矩阵奇异阵,高斯方法失败!:");getch();}double gaussl(double a[][N+1],double b[],double x[],int t[])//a传入增广矩阵(有效元素为a[1,1]...a[n,n+1]),x负责传入迭代初值并返回解向量//(有效值为x[1]...x[n]);返回值:系数矩阵行列式值detA{double det=1.0,F,m,temp;int i,j,k,r,s;void disp(double a[][N+1],double b[],int x[]);// printf("消元前增广矩阵:\n");//disp(a,b,t);for(k=1;k<N;k++){temp=a[k][k];r=k;s=k;for(i=k;i<=N;i++)for(j=k;j<=N;j++)if(fabs(temp)<fabs(a[i][j])){temp=a[i][j];r=i;s=j;}//选主元,选取ik,jkif(a[r][s]==0)return 0;if(r!=k){for(j=k;j<=N;j++){a[k][j]+=a[r][j];a[r][j]=a[k][j]-a[r][j];a[k][j]-=a[r][j];}b[k]+=b[r];b[r]=b[k]-b[r];b[k]-=b[r];det=-det;printf("交换第%d, %d行:\n",k,r);disp(a,b,t);}if(s!=k){for(i=0;i<=N;i++){a[i][k]+=a[i][s];a[i][s]=a[i][k]-a[i][s];a[i][k]-=a[i][s];}t[k]+=t[s];t[s]=t[k]=t[s];t[k]-=t[s];det=-det;printf("交换第%d, %d列:\n",k,s);disp(a,b,t);}for(i=k+1;i<=N;i++){m=a[i][k]/a[k][k];for(j=1;j<=k;j++)a[i][j]=0.0;for(j=k+1;j<=N;j++)a[i][j]-=m*a[k][j];b[i]-=m*b[k];} //消元计算printf("第%d次消元:\n",k);disp(a,b,t);det*=a[k][k];} //大FOR循环结束x[N]=b[N]/a[N][N];for(i=N-1;i>0;i--){F=0.0;for(j=i+1;j<=N;j++)F+=a[i][j]*x[j];x[i]=(b[i]-F)/a[i][i];}//回代计算det*=a[N][N];return det;}void disp(double a[][N+1],double b[],int x[])//显示选主元及消元运算中间增广矩阵结果{int i,j;for(i=1;i<=N;i++){for(j=1;j<=N;j++)printf("%f\t",a[i][j]);printf("| x%d = %f\n",x[i],b[i]);}}运行及结果显示:实验十一:LU 分解算法命名(源程序.cpp 及工作区.dsw ):LU问题:利用LU 法求解方程组 ⎥⎥⎥⎦⎤⎢⎢⎢⎣⎡=⎥⎥⎥⎦⎤⎢⎢⎢⎣⎡⎥⎥⎥⎦⎤⎢⎢⎢⎣⎡472111312613321x x x //LU.cpp#include<math.h> #include<stdio.h> #include<conio.h> #define N 3static aa[N][N]={{3,1,6},{2,1,3},{1,1,1}}; static bb[N]={2,7,4};void main() {int i,j;double a[N+1][N+1],b[N+1];void solve(double a[][N+1],double b[N+1]); int LU(double a[][N+1]); for(i=1;i<=N;i++) { for(j=1;j<=N;j++) a[i][j]=aa[i-1][j-1]; b[i]=bb[i-1]; }if(LU(a)==1){printf("矩阵L如下\n");for(i=1;i<=N;i++){for(j=1;j<=i;j++)if(i==j)printf("%12d ",1);else printf("%12f",a[i][j]);printf("\n");}printf("\n矩阵U如下\n");for(i=1;i<=N;i++){for(j=1;j<=N;j++)if(i<=j)printf("%12f",a[i][j]);else printf("%12s","");printf("\n");}solve(a,b);for(i=1;i<=N;i++)printf("x[%d]=%f ",i,b[i]);printf("\n");}else printf("\nthe LU method failed!\n");getch();}int LU(double a[][N+1])//对N阶矩A阵进行LU分解,结果L、U存放在A的相应位置{int i,j,k,s;double m,n;for(i=2;i<=N;i++)a[i][1]/=a[1][1];for(k=2;k<=N;k++){for(j=k;j<=N;j++){m=0;for(s=1;s<k;s++)m+=a[k][s]*a[s][j];a[k][j]-=m;}if(a[k][k]==0){printf("a[%d][%d]=%d ",k,k,0);return -1;//存在元素akk为0}for(i=k+1;i<=N;i++){n=0;for(s=1;s<k;s++)n+=a[i][s]*a[s][k];a[i][k]=(a[i][k]-n)/a[k][k];}}return 1;//正常结束}void solve(double a[][N+1],double b[N+1])//利用分解的LU求x//回代求解,L和U元素均在A矩阵相应位置;b存放常数列,返回时存放方程组的解{double y[N+1],F;int i,j;y[1]=b[1];for(i=2;i<=N;i++){F=0.0;for(j=1;j<i;j++)F+=a[i][j]*y[j];y[i]=b[i]-F;}b[N]=y[N]/a[N][N];for(i=N-1;i>0;i--){F=0.0;for(j=N;j>i;j--)F+=a[i][j]*b[j];b[i]=(y[i]-F)/a[i][i];}}运行及结果显示:实验十二:Guass-Sediel 算法命名(源程序.cpp 及工作区.dsw ):GS问题:利用G -S 法求解方程组 ⎪⎩⎪⎨⎧=+--=-+-=--2.453.82102.7210321321321x x x x x x x x x (精度为41021-⨯)//Guass_sediel.cpp#include "iostream.h"#include "math.h"#include "stdio.h"#include<conio.h>#define N 3 //方程的阶数#define MaxK 100 //最大迭代次数#define EPS 0.5e-4 //精度控制static double aa[N][N]={{10,-1,-2},{-1,10,-2},{-1,-1,5}};static double bb[N]={7.2,8.3,4.2};void main(){int i,j;double x[N+1];double a[N+1][N+1],b[N+1];int GaussSeidel(double a[][N+1],double b[],double x[]);for(i=1;i<=N;i++){for(j=1;j<=N;j++)a[i][j]=aa[i-1][j-1];b[i]=bb[i-1];x[i]=0;}if(GaussSeidel(a,b,x)==1){printf("the roots is:");for(i=1;i<=N;i++)printf(" x[%d]=%f ",i,x[i]);printf("\n");}else printf("\nthe G-S method failed!\n");getch();}int GaussSeidel(double a[][N+1],double b[],double x[])//a传入系数矩阵(有效元素为a[1,1]...a[n,n]),b为方程组右边常数列,x传入迭代初值并返回解向量//x**(k+#x)=Gx**(k)+f{int k=1,i,j;double m,max,t[N+1];while(true){printf("k=%d:",k);max=0.0;for(i=1;i<=N;i++){if(a[i][i]==0)return -1;//存在元素akk为0m=0.0;t[i]=x[i];for(j=1;j<=N;j++)if(j!=i)m+=a[i][j]*x[j];x[i]=(b[i]-m)/a[i][i];if(max<fabs(x[i]-t[i]))max=fabs(x[i]-t[i]);printf(" x[%d]=%f ",i,x[i]);}printf("\n");if(max<EPS)return 1;//正常结束elsek++;if(k>MaxK)return -2;//迭代次数越界}}运行及结果显示:实验十三:SOR 算法命名(源程序.cpp 及工作区.dsw ):sor问题:利用SOR 法求解方程组⎥⎥⎥⎥⎦⎤⎢⎢⎢⎢⎣⎡=⎥⎥⎥⎥⎦⎤⎢⎢⎢⎢⎣⎡⎥⎥⎥⎥⎦⎤⎢⎢⎢⎢⎣⎡----111141111411114111144321x x x x (精度为51021-⨯) //SOR.cpp#include "math.h"#include "stdio.h"#include "conio.h"#define N 4#define MaxK 1000#define EPS 0.5e-5static double aa[N][N]={{-4,1,1,1},{1,-4,1,1},{1,1,-4,1},{1,1,1,-4}}; static double bb[N]={1,1,1,1};void main(){int i,j;double x[N+1];double a[N+1][N+1],b[N+1];int Sor(double a[][N+1],double b[],double w,double x[]);for(i=1;i<=N;i++){for(j=1;j<=N;j++)a[i][j]=aa[i-1][j-1];b[i]=bb[i-1];x[i]=0;}if(Sor(a,b,1.3,x)==1){printf("the roots is:");for(i=1;i<=N;i++)printf(" x[%d]=%f ",i,x[i]);printf("\n");}else printf("\nthe G-S method failed!\n");getch();}int Sor(double a[][N+1],double b[],double w,double x[]) {int i,j,k;double loft,comb;for(k=0;k<=N;k++)x[k]=0;for(i=1;i<=MaxK && fabs(comb)>EPS;i++){printf("k=%d:\t",i);comb=0;for(k=1;k<=N;k++){loft=b[k];for(j=1;j<N+1;j++)loft-=a[k][j]*x[j];if(a[k][k]==0)return -1;else loft=w*loft/a[k][k];x[k]=x[k]+loft;printf("x[%d]=%10f \t",k,x[k]);if(fabs(loft)>comb)comb=fabs(loft);}printf("\n");}if(i>MaxK)return -2;elsereturn 1;}运行结果(w=1)=。
武汉理工大学学生实验报告书实验课程名称数值分析开课学院计算机科学与技术学院指导老师姓名学生姓名学生专业班级2010—2010学年第一学期实验课程名称:数值分析第二部分:实验调试与结果分析(可加页)一、调试过程(包括调试方法描述、实验数据记录,实验现象记录,实验过程发现的问题等)(1)用拉格朗日插值法计算时,输入及运行结果如下:拉格朗日插值法牛顿插值法(2)利用二次插值计算时,输入及运行结果如下:拉格朗日插值法牛顿插值法(3)用艾尔米特插值法计算时,f(x)的插值多项式H5(x)=(1+4*x)*(x-0.5)*(x-0.5)*(x-2)*(x-2)+(3.90807-6.03838*x)*(x-2)*(x-2)*x*x+(2.34573-4.16674*x)*x*x*(x-0.5)*(x-0.5)(4)各插值算法的精度差异比较经过比较,拉格朗日插值法要比牛顿插值法算法的计算量多一些,拉格朗日插值法后一次计算时用到了前一次计算的结果,提高了运算的效率,但拉格朗日插值法在构造艾尔米特插值法时很方便,将坐标点和对应的导数结合起来的精度比线性插值的精度又要高一些。
但从实验数据来看,在坐标不是很多的情况下,已知的点越多精度也就相对较高。
对于实验要求的第二组数据用拉格朗日插值法(或者牛顿插值法)实验结果如下:一下分别是二阶、三阶、四阶、五阶插值得到的结果以上只是实验结果的一部分,改变插值的位置时,得到的实验结果精度也是有所不同的。
由以上结果分析可知,插值次数并不是越多越好,多了反而会让结果更加偏离真实结果,这充分说明了高次插值存在“病态性质”,在已知点很多的情况下应该采用分段低次插值,将拉格朗日插值法和牛顿插值法运用到分段低次插值法当中,这样得到的结果可能胡更加精确。
#include<stdio.h>
#include<math.h>
float f(float x) //计算ex的值
{
return (exp(x));
}
float g(float x) //计算根号x的值
{
return (pow(x,0.5));
}
void linerity () //线性插值
{
float px,x;
float x0,x1;
printf("请输入x0,x1的值\n");
scanf("%f,%f",&x0,&x1);
printf("请输入x的值: ");
scanf("%f",&x);
px=(x-x1)/(x0-x1)*f(x0)+(x-x0)/(x1-x0)*f(x1);
printf("f(%f)=%f \n",x,px);
}
void second () //二次插值
{
float x0,x1,x2,x,px;
x0=0;
x1=0.5;
x2=2;
printf("请输入x的值:");
scanf("%f",&x);
px=((x-x1)*(x-x2))/((x0-x1)*(x0-x2))*f(x0)+((x-x0)*(x-x2))/((x1-x0)*(x1-x2))*f(x1)+((x-x0)* (x-x1))/((x2-x0)*(x2-x1))*f(x2);
printf("f(%f)=%f\n",x,px);
}
void Hermite () //Hermite插值
{
int i,k,n=2;
int flag1=0;
printf("Hermite插值多项式H5(x)=");
for(i=0;i<=n;i++)
{
int flag=0;
flag1++;
if(flag1==1)
{
printf("y%d[1-2(x-x%d)*(",i,i);
}
else
{
printf("+y%d[1-2(x-x%d)*(",i,i);
}
for(k=0;k<=n;k++)
{
if(k!=i)
{
flag++;
if(flag==1)
{
printf("(1/x%d-x%d)",i,k);
}
else
{
printf("+(1/x%d-x%d)",i,k);
}
}
}
printf(")]*(");
for(k=0;k<=n;k++)
{
if(i!=k)
{
printf("[(x-x%d)/(x%d-x%d)]2",i,k,i);
}
}
printf(")");
}
printf("\n");
}
void sectionl () //分段线性插值
{
float x[5]={2.0,2.1,2.2,2.3,2.4};
float y;
printf("请输入y:");
scanf("%f",&y);
if(y>=2.0&&y<2.1)
{
float px;
px=((y-x[1])/(x[0]-x[1]))*g (x[0])+((y-x[0])/(x[1]-x[0]))*g (x[1]);
printf("f(%f)=%f\n",y,px);
}
else if(y>=2.1&&y<2.2)
{
float px;
px=((y-x[2])/(x[1]-x[2]))*g (x[1])+((y-x[1])/(x[2]-x[1]))*g (x[2]);
printf("f(%f)=%f\n",y,px);
}
else if(y>=2.2&&y<2.3)
{
float px;
px=((y-x[3])/(x[2]-x[3]))*g (x[2])+((y-x[2])/(x[3]-x[2]))*g (x[3]);
printf("f(%f)=%f\n",y,px);
}
else if(y>=2.3&&y<2.4)
{
float px;
px=((y-x[4])/(x[3]-x[4]))*g (x[3])+((y-x[3])/(x[4]-x[3]))*g (x[4]);
printf("f(%f)=%f\n",y,px);
}
else if(y>2.4) printf("**********ERROR!******************\n"); }
void sectionp ()
{
int i;
float a[5]={2.0,2.1,2.2,2.3,2.4};
float x,y;
printf("input the data: x?\n");
scanf("%f",&x);
if(x<a[1])
{i=1;goto loop;}
if(x>a[4])
{i=4;goto loop;}
i=1;
loop1:i++;
if(x>a[i])goto loop1;
if(fabs(x-a[i-1])<=fabs(x-a[i]))i=i-1;
loop:y=g(a[i-1])*(x-a[i])*(x-a[i+1])/((a[i-1]-a[i])*(a[i-1]-a[i+1]));
y=y+g(a[i])*(x-a[i-1])*(x-a[i+1])/((a[i]-a[i-1])*(a[i]-a[i+1]));
y=y+g(a[i+1])*(x-a[i-1])*(x-a[i])/((a[i+1]-a[i-1])*(a[i+1]-a[i]));
printf("f(%f)=%f\n",x,y);
}
int main()
{
char flag1='y';
while(flag1=='y')
{
int flag=0;
printf("*******[1]:线性插值***************\n");
printf("*******[2]:二次插值***************\n");
printf("*******[3]:Hermite插值************\n");
printf("*******[4]:分段线性插值***********\n");
printf("*******[5]:分段抛物线插值*********\n");
printf("请输入:");
scanf("%d",&flag);
switch(flag)
{
case 1:
linerity ();break;
case 2:
second ();break;
case 3:
Hermite ();break;
case 4:
sectionl ();break;
case 5:sectionp ();break;
default:
printf("error!!\n");
}
printf("是否继续?y/n \n");
getchar();
scanf("%c",&flag1);
}
return 0;
}。