c++数值分析上机实验

  • 格式:doc
  • 大小:196.00 KB
  • 文档页数:24

张体强 1026222 海测一第一章舍入误差和数值稳定性1:例题利用递推公式计算定积分⎰+1n5xdxx方法一:利用递归公式151--=n n y ny (n=0,1,2,3…….20)方法二:利用递推公式n n y ny 51511-=-(n=0,1,2,3…….20)这两种方法的思路是: 1:逆代初值2:根据范围来确定循环次数 3:根据逆代函数确定逆代形似 4:如何排版1.1:方法一的C 语言实现: #include <stdio.h> #include<conio.h> #include<math.h> main() {float y0=log(6.0)-log(5.0),y1;int n=1;printf("y[0]=%-20f",y0);while(n<=20){y1=1.0/n-5*y0;printf("y[%d]=%-20f",n,y1);y0=y1;n++;if(n%3==0)printf("\n");}}1.2:方法二的c语言实现:#include <stdio.h>#include<math.h>main(){float y20=(1/105.0+1/126.0)/20,y19;int n=20;printf("y[20]=%-20f",y20);while(n>0){y19=1.0/(5*n)-y20/5;printf("y[%d]=%-20f",n-1,y19);y20=y19;n--;if(n%3==0)printf("\n");}}通过两种计算方式可以看出第二种的算法收敛2:课后习题13根据pn=(10/3)*p n-1-p n-2可知道pn的相对误差限为en=(10/3)*e n-1-e n-2 n=2 3 …….根据书中的例题方法很难比较误差是否增大,现在经过以下递归程序可以看出其结果:#include <stdio.h>double fact(int n);void main(){int n;double result;printf("Input n:");scanf("%d",&n);result=fact(n);if (result==-1)printf("Input error");/* n的值输入不正确*/elseprintf("wc=%.5f\n",result);}double fact(int n){if(n<2)return -1;elseif(n==2) /* 终止条件*/return 0.005;/* 起始误差为0.005*/elsereturn (10.0/3)*fact(n-1)-fact(n-2);/* 调用递归*/}结果表明当n=4时误差要大于n=1时的误差,所以不稳定。

17:编写程序如下#include <stdio.h>void main(){float i,j,n;float sum1=0;float sum2=0;float zhi,wc1,wc2;for(i=2;i<=100;i++){sum1+=1/(i*i-1);}printf("sum1=%f\n",sum1);for(j=100;j>=2;j--){sum2+=1/(j*j-1);}printf("sum2=%f\n",sum2);zhi=1.0/2*(3.0/2-(1.0/n)-1.0/(n+1));printf("zhi=%f\n",zhi);wc1=zhi-sum1;wc2=zhi-sum2;printf("wc1=%f\n",wc1);printf("wc2=%f\n",wc2);}三种情况结果对比:通过上图可以看出:按从大到小的顺序计算的值与精确值有较大的误差,而按从小到大的顺序计算的值与精确值较吻合,误差较小。

计算机在进行数值计算时会出现“大数吃小数”的现象,导致计算结果的精度有所降低,我们在计算机中进行同号数的加法时,采用绝对值较小者先加的算法,其结果的相对误差较小。

第二章二分法查找和牛顿逆代1:二分法查找算法设计给定区间[a b],并设f(a)与f(b)符号相反,取ε为根的容许误差,δ为|f(x)|的容许误差1:令c=(a+b)/22:如果(c - a)<ε或就输出结果,否者执行33:如果f(a)f(c)>0,则把a的值和函数值复制给c和c的函数值,否者就把b的值和函数值复制给c和c的函数值1.1:例题:求方程分f(x)=X^3+X^2-3X-3=0在1.5附近的根(以后在这上面修改一下即可)#include <stdio.h>#include<math.h>#include<conio.h>#include<stdlib.h>#include <windows.h>#define EPS 5e-6#define wucha 1e-6float erfenfa(float,float,float(*f)(float));float f(float x);void main(){float a=1,b=2;float x;system("cls");//清除文本模式窗口x=erfenfa(a,b,f);printf("\n原方程的根是:%f",x);getch();//:从控制台读取一个字符,但不显示在屏幕上}float erfenfa(float a,float b,float(*f)(float)){float c,fc,fa=f(a),fb=f(b);int n=1;printf("二分法查找次数c\t\t f(c)\n");while(1){if(fa*fb>0) exit(1);c=(a+b)/2,fc=f(c);if(fabs(fc)<wucha) break;else if(fa*fc<0){b=c;fb=fc;}else{a=c;fa=fc;}if(b-a<EPS)break;printf("%d \t\t%f\t\t%f\n",n++,c,fc);}return c;}float f(float x){return x*x*x+x*x-3*x-3;}2:牛顿逆代算法设计给定初始值x0,ε为根的容许误差,η为|f(x)|的容许误差,n为逆代次数的容许值。

1 计算x1=x0-f(x0)/f’(x0)。

2 if(eps(x1-x0)<ε则输出x1,程序结束,否者执行33 令x0=x1,回头执行1利用c语言和matlab实现第二十题20:(1):方程为x*x*x/3-1,误差靠输入//在纸上画出图形,估计三个值的范围//编写一个程序,用牛顿逆代求根.#include "stdafx.h"#include<stdio.h>#include<math.h>float fx(float x);float fdx(float x);void main(){float x0,x1,wc,m;int k=0;printf("请输入允许误差");/*输入逆代误差*/scanf("%f",&wc);printf("请输入初值,初值不能为-1,1\n");/*初值为1和-1导数没有意义*/ scanf("%f",&x0);do{m=-fx(x0)/fdx(x0);x1=x0+m;x0=x1;}while(fabs(m)>wc);printf("逆代结果为:%f",x0);}float fx(float x)/*函数表达式*/{float y;y=x*x*x/3-x;return(y);}float fdx(float x)/*导数*/{float yd;yd=x*x-1;return(yd);}运行结果:一个根为:1.73205一个根为:-1.73205一个根为:0(2)题目的意思和方法待请教老师。

利用matlab编写(1)如下x=-4:0.1:4;y=x.^3./3-x;plot(x,y,'r');grid on;function x=newton(fname,dfname,x0,e)if nargin<4,e=1e-4;endx=x0;x0=x+2*e;while abs(x0-x)>ex0=x;x=x0-feval(fname,x0)/feval(dfname,x0);end%定义牛顿逆代fun=inline('x^3/3-x');dfun=inline('x^2-1');format long;a=newton(fun,dfun,-2,1e-6),format short %当在-2附近时,求根a =-1.73205080756888%复制上面代码,修改求其当在0附近时,求根fun=inline('x^3/3-x');dfun=inline('x^2-1');format long;b=newton(fun,dfun,0,1e-6),format shortb=%复制上面代码,修改求其在2附近时,求根fun=inline('x^3/3-x');dfun=inline('x^2-1');format long;c=newton(fun,dfun,2,1e-6),format short c =1.73205080756888利用matlab ,在定义好牛顿逆代后,只需要三句代码可求其根,方法简单,最主要的是牛顿逆代可以以后再次调用第三章线性方程组的数值解法(利用c 语言和matlab 实现)3.1 一般方法及AX=B 得到X=A -1B例如方程 104325848332=++=++=++z y x zy x z y x 的解 输入代码如下A=[1 2 3;8 4 8;1 3 4]; B=[3;25;10]; X=A\B 结果为 X = 10.2500 28.2500 -21.2500所以x=10.2500, y=28.2500, z=-21.25003.2 列主元高斯消去法(matlab 和c 语言的实现) 3.2.1 Matlab 实现列主元高斯消去104325848332=++=++=++z y x z y x z y x在matlab 输入一下程序即可(实现编号gauss 保存在自己的常用函数盘里,这里代码省去)A=[1 2 3;8 4 8;1 3 4]; B=[3;25;10]; gauss(A,B) 结果为 x=10.2500 y=28.2500 z=-21.25003.2.2 c 语言实现列主元高斯消去求解(可参考《计算方法》3版)例如方程 104325848332=++=++=++z y x z y x z y x 的解 输入代码如下1 将方程的增广矩阵[A|b]=(a ij )n x (n+1)表示2 消元过程 对 k=1,2,3,4…………n-13 选主元4 交换5 消元#include<stdlib.h>#include <stdio.h>#include<conio.h>#include<malloc.h>#include<math.h>void main(){int i;float *x;float c[3][4]={1,2,3,3,8,4,8,25,1,3,4,10};float *liezhuyuan(float *c,int n);x=liezhuyuan(c[0],3);for(i=0;i<=2;i++)printf("x[%d]=%f\n",i,x[i]);getch();}float *liezhuyuan(float *c,int n){int i,j,t,k;float *x,p;x=(float *)malloc(n*sizeof(float));for(i=0;i<=n-2;i++){k=i;for(j=j+1;j<=n-1;j++);if(fabs(*(c+j*(n+1)+i))>(fabs(*(c+k*(n+1)+i)))) k=j;if(k==i)for(j=i;j<=n;j++){p=*(c+i*(n+1)+j);*(c+i*(n+1)+j)=*(c+k*(n+1)+j);*(c+k*(n+1)+j)=p;}for(j=i+1;j<=n-1;j++){p=(*(c+j*(n+1)+i))/(*(c+i*(n+1)+i));for(t=i;t<=n;t++)*(c+j*(n+1)+t)-=p*(*(c+i*(n+1)+t));}}for(i=n-1;i>=0;i--){for(j=n-1;j>=i+1;j--)(*(c+i*(n+1)+n))-=x[j]*(*(c+i*(n+1)+j)); x[i]=*(c+i*(n+1)+n)/(*(c+i*(n+1)+i)); } return x; }3.3 雅可比逆代(matlab 代码略)例如方程 104325848332=++=++=++z y x z y x z y x 的解 输入代码如下#include<stdio.h> #include<conio.h>#include<malloc.h> #include<math.h> #define EPS 1e-6 #define MAX 100float *jacobi(float a[3][4],int n)//定义了一个指针函数 {float *x,*y,epshe,s; int i,j,k=0;x=(float *)malloc(n*sizeof(float));//说明有几个未知数y=(float *)malloc(n*sizeof(float));//逆代后结果for(i=0;i<n;i++)x[i]=0;while(1){epshe=0;k++;for(i=0;i<n;i++){s=0;for(j=0;j<n;j++){if(j==i)continue;s+=a[i][j]*x[j];}y[i]=(a[i][n]-s)/a[i][i];epshe+=fabs(y[i]-x[i]);//y[i]为逆代值,x[i]为前面的逆代得结果}if(epshe<EPS){printf("逆代次数为:%d\n",k);return y;}if(k>=MAX){printf("这个逆代结果为发散");return y;}for(i=0;i<n;i++)x[i]=y[i];//把逆代的值赋给y[i],以便后面的逆代,直到输出}}main(){int i;float a[3][4]={1,2,3,3,8,4,8,25,1,3,4,10};float *x;x=(float *)malloc(3*sizeof(float));x=jacobi(a,3);for(i=0;i<3;i++)printf("\nx[%d]=%f\n",i,x[i]);getch();}所以上面的方程不能雅可比逆代格式,当然有的方程可以例如:修改一下方程组的系数float a[3][4]={5,2,1,8,2,8,-3,21,1,-3,-6,1};结果为第四章插值与最小二乘发拟合牛顿逆代和Lagrange结果一样,这里我只研究Lagrange逆代。