实 验 报 告
实验课程:MATLAB数值分析
学生姓名:
学 号: 20103010
学 院:
专 业:
指导老师:
20##年12月28日
一、问题描述
考虑如下Dirichlet问题
其中为正方形区域的边界,类似于模型问题,我们得到差分方程
得到系数矩阵
A=其中B=-I,I为n-1阶单位矩阵S’为对角元为1+次对角元为的n-1阶的对称三对角矩阵。对=sin(xy),=,n=20.用超松弛以及共轭梯度求解差分方程的解。
二、Matlab代码及其结果
Gauss-Seidel方法:
n=20;
h=1/n;
a=h*h/4;
m=n*n;
S=zeros(n-1,n-1);
for i=1:n-1
S(i,i)=1+h*h/4;
end
for i=2:n-1
S(i,i-1)=-1/4;
end
for i=1:n-2
S(i,i+1)=-1/4;
end
B=zeros(n-1,n-1);
for i=1:n-1
B(i,i)=-1/4;
end
A=zeros((n-1)*(n-1),(n-1)*(n-1));
for i=1:n-1
A((i-1)*(n-1)+1:i*(n-1),(i-1)*(n-1)+1:i*(n-1))=S;
end
for i=1:n-2
A(i*(n-1)+1:(i+1)*(n-1),(i-1)*(n-1)+1:i*(n-1))=B;
end
for i=1:n-2
A((i-1)*(n-1)+1:i*(n-1),i*(n-1)+1:(i+1)*(n-1))=B;
End
b=[1:(n-1)*(n-1)]'*0;
j=1;
b(1)=a*sin(1/m)+2*a;
b(n-1)=a*sin((n-1)/m)+a*((n-1)*(n-1))+a*(1+n*n);
for i=2:n-2
b(i)=a*sin(i*j/m)+a*i*i;
end
for j=2:n-2
b((j-1)*(n-1)+1)=a*sin(1*j/m)+a*j*j;
b(j*(n-1))=a*sin((n-1)*j/m)+a*(j*j+n*n);
for i=(j-1)*(n-1)+2:j*(n-1)-1
b(i)=a*sin((i-(j-1)*(n-1))*j/m);
end
end
j=n-1;
b((n-2)*(n-1)+1)=a*sin(1*j/m)+(n-1)*(n-1)*a+(1+n*n)*a;
for i=(n-2)*(n-1)+2:(n-1)*(n-1)-1
b(i)=a*sin((i-(n-2)*(n-1))*j/m)+1/4+((i-(n-2)*(n-1))*(n-1))*a;
end
b((n-1)*(n-1))=a*sin((n-1)*(n-1)/m)+(n*n+(n-1)*(n-1))/(m*2);
y=A\b
n=length (b);
Y=zeros (n,1);
Y0=Y;
Y1=Y;
w=1.7
U=zeros (n,n);
for i=1:n
for j=i+1:n
U (i,j)=A (i,j);
end
end
DL=A-U;
for II=1:100000
B=-U*Y0+b;
Y1 (1)=B (1)/DL(1,1);
for i=2:n
Y1 (i)=(B (i)-DL (i,1:i-1)*Y1 (1:i-1))/DL(i,i);
end
Y=w*Y1+(1-w)*Y0;
Y0=Y1;
r=A*Y-b;
err=norm (r);
if err<eps
break;
end
end
[II,err]
Y
reshape(Y,19,19)
SOR方法:
n=20;
h=1/n;
a=h*h/4;
m=n*n;
S=zeros(n-1,n-1);
for i=1:n-1
S(i,i)=1+h*h/4;
end
for i=2:n-1
S(i,i-1)=-1/4;
end
for i=1:n-2
S(i,i+1)=-1/4;
end
B=zeros(n-1,n-1);
for i=1:n-1
B(i,i)=-1/4;
end
A=zeros((n-1)*(n-1),(n-1)*(n-1));
for i=1:n-1
A((i-1)*(n-1)+1:i*(n-1),(i-1)*(n-1)+1:i*(n-1))=S;
end
for i=1:n-2
A(i*(n-1)+1:(i+1)*(n-1),(i-1)*(n-1)+1:i*(n-1))=B;
end
for i=1:n-2
A((i-1)*(n-1)+1:i*(n-1),i*(n-1)+1:(i+1)*(n-1))=B;
end
b=[1:(n-1)*(n-1)]'*0;
j=1;
b(1)=a*sin(1/m)+2*a;
b(n-1)=a*sin((n-1)/m)+a*((n-1)*(n-1))+a*(1+n*n);
for i=2:n-2
b(i)=a*sin(i*j/m)+a*i*i;
end
for j=2:n-2
b((j-1)*(n-1)+1)=a*sin(1*j/m)+a*j*j;
b(j*(n-1))=a*sin((n-1)*j/m)+a*(j*j+n*n);
for i=(j-1)*(n-1)+2:j*(n-1)-1
b(i)=a*sin((i-(j-1)*(n-1))*j/m);
end
end
j=n-1;
b((n-2)*(n-1)+1)=a*sin(1*j/m)+(n-1)*(n-1)*a+(1+n*n)*a;
for i=(n-2)*(n-1)+2:(n-1)*(n-1)-1
b(i)=a*sin((i-(n-2)*(n-1))*j/m)+1/4+((i-(n-2)*(n-1))*(n-1))*a;
end
b((n-1)*(n-1))=a*sin((n-1)*(n-1)/m)+(n*n+(n-1)*(n-1))/(m*2);
y=A\b;
Y=b*0
p=Y;
r=Y;
p1=Y;
r1=Y;
r=b-A*Y;
k=0;
normr=r'*r;
while sqrt (normr)>eps
k=k+1
if k==1
p=r
else
beta=normr2/normr;
p=r+beta*p;
normr=normr2;
end
alpha=(normr)/ (p'*A* p);
Y=Y+alpha*p;
r=r-alpha*A*p;
normr2=r'*r;
k;
normr2;
end
sqrt_normr=sqrt (normr2)
k
r
Y
reshape(Y,19,19)
结果图片:
三、C语言代码及其结果
Gauss-Seidel方法:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
int main()
{
int i,j,k;
int m,n,p;
double b[400]={0},A[400][400]={0},U[400]={0};
double P[400]={0},r[400]={0},B[400]={0};
double a;
double h;
double eps;
double normr=0.0,normr2,alpha,beta;
double sum,sumr,sumA,sqrt_normr;
printf("n= \n");
scanf("%d",&n);
printf("eps= \n");
scanf("%lf",&eps);
printf("%lf\n",eps);
h=1.0/n;
m=n*n;
p=n-1;
printf("%lf\n",h);
a=h*h/4;
printf("%d,%d,%lf,%lf\n",m,p,h,a);
j=1;
b[1]=a*sin(1.0/m)+2*a;
b[n-1]=a*sin(1.0*p/m)+a*(p*p)+a*(1+n*n);
for(i=2;i<=n-2;i++)
b[i]=a*sin(1.0*i*j/m)+a*i*i;
for(j=2;j<=n-2;j++)
{
b[(j-1)*p+1]=a*sin(1.0*j/m)+a*j*j;
b[j*p]=a*sin(1.0*p*j/m)+a*(j*j+n*n);
for(i=(j-1)*p+2;i<=j*p-1;i++)
b[i]=a*sin((i-(j-1)*p)*j*1.0/m);
}
/*for(i=17*p+2;i<=18*p;i++)
printf("%0.10lf\n",b[i]);*/
j=n-1;
b[(p-1)*p+1]=a*sin(1.0*j/m)+p*p*a+a*(1+n*n);
for(i=(p-1)*p+2;i<=p*p-1;i++)
b[i]=a*sin(1.0*(i-(p-1)*p)*j/m)+1.0/4+a*(i-(p-1)*p)*(i-(p-1)*p);
b[p*p]=a*sin(1.0*p*p/m)+(n*n+p*p)*2*a;
A[1][1]=1+a;
A[1][2]=-0.25;
A[p*p][p*p-1]=-0.25;
A[p*p][p*p]=1+a;
for(i=2;i<=p*p-1;i++)
{ A[i][i-1]=-0.25;
A[i][i]=1+a;
A[i][i+1]=-0.25;
}
for(i=n;i<=p*p;i++)
{ A[i-n+1][i]=-0.25;
A[i][i-n+1]=-0.25;
}
for(j=2;j<=n-1;j++)
{ A[(j-1)*p][(j-1)*p+1]=0.0;
A[(j-1)*p+1][(j-1)*p]=0.0;
}
for(i=1;i<=p*p;i++)
{ sum=0.0;
for(j=1;j<=p*p;j++)
sum=sum+A[i][j]*U[j];
r[i]=b[i]-sum;
}
for(i=1;i<=p*p;i++)
normr=normr+r[i]*r[i];
k=0;
do
{
k=k+1;
if(k==1)
{
for(i=1;i<=p*p;i++)
P[i]=r[i];
}
else
{
beta=normr2/normr;
for(i=1;i<=p*p;i++)
P[i]=r[i]+beta*P[i];
normr=normr2;
}
sumr=0.0; //r的范数//
for(i=1;i<=p*p;i++)
sumr=sumr+r[i]*r[i];
for(i=1;i<=p*p;i++) //求A*P//
{
B[i]=0.0;
for(j=1;j<=p*p;j++)
B[i]=B[i]+A[i][j]*P[j];
}
sumA=0.0; //A关于P的共轭乘积//
for(i=1;i<=p*p;i++)
sumA=sumA+P[i]*B[i];
alpha=sumr/sumA; //求alpha//
for(i=1;i<=p*p;i++)
U[i]=U[i]+alpha*P[i];
for(i=1;i<=p*p;i++)
r[i]=r[i]-alpha*B[i];
normr2=0.0;
for(i=1;i<=p*p;i++)
normr2=normr2+r[i]*r[i];
sqrt_normr=sqrt(normr);
}
while(sqrt_normr>eps);
printf("U=\n");
for(i=1;i<=p*p;i++)
printf("%lf\n",U[i]);
printf("sqrt_normr=%lf\n",sqrt_normr);
printf("k=%d\n",k);
system("pause");
return 0;
}
SOR方法:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
int main()
{
int i,j,k;
int n,m,p;
double a,h,eps;
double w,sum,norm,sumB,sumr;
double u[400]={0},r[400]={0},B[400]={0};
double u1[400]={0},u0[400]={0},b[400]={0};
double A[400][400]={0};
printf("n= \n");
scanf("%d",&n);
printf("eps= w= \n");
scanf("%lf",&eps);
scanf("%lf",&w);
printf("eps=%lf\n",eps);
printf("w=%lf\n",w);
h=1.0/n;
m=n*n;
p=n-1;
printf("%lf\n",h);
a=h*h/4;
printf("%d,%d,%lf,%lf\n",m,p,h,a);
j=1;
b[1]=a*sin(1.0/m)+2*a;
b[n-1]=a*sin(1.0*p/m)+a*(p*p)+a*(1+n*n);
for(i=2;i<=n-2;i++)
b[i]=a*sin(1.0*i*j/m)+a*i*i;
for(j=2;j<=n-2;j++)
{
b[(j-1)*p+1]=a*sin(1.0*j/m)+a*j*j;
b[j*p]=a*sin(1.0*p*j/m)+a*(j*j+n*n);
for(i=(j-1)*p+2;i<=j*p-1;i++)
b[i]=a*sin((i-(j-1)*p)*j*1.0/m);
}
j=n-1;
b[(p-1)*p+1]=a*sin(1.0*j/m)+p*p*a+a*(1+n*n);
for(i=(p-1)*p+2;i<=p*p-1;i++)
b[i]=a*sin(1.0*(i-(p-1)*p)*j/m)+1.0/4+a*(i-(p-1)*p)*(i-(p-1)*p);
b[p*p]=a*sin(1.0*p*p/m)+(n*n+p*p)*2*a;
A[1][1]=1+a;
A[1][2]=-0.25;
A[p*p][p*p-1]=-0.25;
A[p*p][p*p]=1+a;
for(i=2;i<=p*p-1;i++)
{ A[i][i-1]=-0.25;
A[i][i]=1+a;
A[i][i+1]=-0.25;
}
for(i=n;i<=p*p;i++)
{ A[i-n+1][i]=-0.25;
A[i][i-n+1]=-0.25;
}
for(j=2;j<=n-1;j++)
{ A[(j-1)*p][(j-1)*p+1]=0.0;
A[(j-1)*p+1][(j-1)*p]=0.0;
}
k=0;
do
{
k=k+1;
for(i=1;i<=p*p;i++) //求B=-U*u0+b U用A代替
{ sumB=0.0;
for(j=i+1;j<=p*p;j++)
sumB=sumB+A[i][j]*u0[j];
B[i]=-sumB+b[i];
}
u1[1]=1.0*B[1]/A[1][1];
for(i=2;i<=p*p;i++) //求u1
{ sum=0.0;
for(j=1;j<=i-1;j++)
sum=sum+A[i][j]*u1[j];
u1[i]=1.0*(B[i]-sum)/A[i][i];
}
for(i=1;i<=p*p;i++) //求解u
u[i]=w*u1[i]+(1-w)*u0[i];
for(i=1;i<=p*p;i++) //求u0
u0[i]=u1[i];
for(i=1;i<=p*p;i++) //求残量r
{ sumr=0.0;
for(j=1;j<=p*p;j++)
sumr=sumr+A[i][j]*u[j];
r[i]=sumr-b[i];
}
norm=0.0;
for(i=1;i<=p*p;i++)//求r的范数
norm=norm+r[i]*r[i];
norm=sqrt(norm);
}
while( norm>eps);
printf("k=%d\n",k);
printf("norm=%lf\n",norm);
for(i=1;i<=p*p;i++)
printf("%lf\n",u[i]);
system("pause");
return 0;
}
运行结果:
参考文献
【1】 徐树方,高立,张平文,数值线性代数。北京大学出版社,2010.
【2】 周品,何正风,MATLAB数值分析。机械工业出版社,2009.