实验要求:
分别用雅可比算法和高斯-塞德尔算法求解给定的线性方程组。
函数接口定义:
int Jacobi( int n, double a[][MAX_SIZE], double b[], double x[], double TOL, int MAXN );
int Gauss_Seidel( int n, double a[][MAX_SIZE], double b[], double x[], double TOL, int MAXN );
两函数的接口定义是一致的:n为矩阵a的维数,MAX_SIZE是由裁判程序定义的矩阵最大维数,b是方程组中的常向量,x传入叠代初始向量,求得的解将存储在x中返回;TOL是需要达到的精度上限,MAXN是叠代最大次数。函数的返回值为整数,有以下4种可能:
- -2:若迭代算法不收敛。这里判断不收敛的根据是当的某个分量值超出了最大区间[-bound, bound],其中bound是由裁判程序定义的常数;
- -1:若矩阵有一列全为0,则方程组没有唯一解;
- 0:若算法经过MAXN次叠代后还没有达到精度要求;
- K:若算法经过K次叠代达到了精度要求。这时求得的解存储在x中。
这里必须注意到,如我们在第五章中讨论过的,在两种算法的公式中,A的对角元aii都出现在分母上,所以为了算法的稳定,我们必须采取措施使得对角元的绝对值尽可能大。因为叠代中A不改变,所以我们可以事先调整好A的对角元。
不同的调整策略可能导致不同的收敛性,本书裁判程序要求的调整策略是:对每
个aii,首先向下扫描该列元素(包括aii)中绝对值最大的那个元,若该元不为0,则通过行交换将该元换到aii的位置。若该元为0,则向上扫描该列元素中绝对值最大的那个元,若该元不为0,则将该元所在行的全部元加到第i行。
实验算法:
雅可比迭代:
高斯赛德迭代:
即在雅可比迭代的基础上,在计算用已经算出来的替换
可能会获得更好的收敛效果。
实验代码:
#include<stdio.h>
#include<math.h>
#define MAX_SIZE 100 /* 矩阵最大维数 */
#define MAX_length 1000
#define bound pow(2, 127) /* 判断叠代发散的边界值 */
#define ZERO 0.000000001 /* 当一个正数小于ZERO就认为该数是0 */
/*做对角元变换,求系数矩阵B和常数项量f*/
double max(double a,double b)
{
if(a>b)
return a;
else
return b;
}
int maix(double a[][MAX_SIZE],double b[],double L[][MAX_SIZE],int n)
{
int i,k,m;
double t,tmp;
for(i=0;i<n;i++)
{
t=0;
for(k=i;k<n;k++)
if(fabs(a[k][i])>t)
{
t=fabs(a[k][i]);
m=k;
}
if(t!=0)
{
if(m!=i)
{
for(k=0;k<n;k++)
{
tmp=a[i][k];
a[i][k]=a[m][k];
a[m][k]=tmp;
}
tmp=b[i];
b[i]=b[m];
b[m]=tmp;
}
}
else
{
for(k=0;k<i;k++)
if(fabs(a[k][i])>t)
{
t=fabs(a[k][i]);
m=k;
}
if(t==0)
return 1;
else
{
for(k=0;k<n;k++)
{
a[i][k]=a[m][k]+a[i][k];
}
b[i]=b[m]+b[i];
}
}
}
/*for(i=0;i<n;i++)
{
for(k=0;k<n;k++)
printf("%.10f ",a[i][k]);
printf("\n");
}
printf("\n");*/
for(i=0;i<n;i++)
{
b[i]=b[i]/a[i][i];
for(k=0;k<n;k++)
{
if(k==i)
L[i][k]=0;
else
L[i][k]=-a[i][k]/a[i][i];
}
}
/*for(k=0;k<n;k++)
printf("%.10f ",b[k]);
printf("\n");
for(i=0;i<n;i++)
{
for(k=0;k<n;k++)
printf("%.10f ",L[i][k]);
printf("\n");
}*/
return 0;
}
int Jacobi( int n, double a[][MAX_SIZE], double b[], double x[], double TOL, int MAXN )
{
double L[MAX_SIZE][MAX_SIZE],xm[MAX_length][MAX_SIZE],f[MAX_SIZE],aa[MAX_SIZE][MAX_SIZE];
double e;
int i,k,m;
for(i=0;i<n;i++)
for(k=0;k<n;k++)
aa[i][k]=a[i][k];
for(k=0;k<n;k++)
f[k]=b[k];
if(maix(aa,f,L,n))
return -1;
m=0;
for(i=0;i<n;i++)
xm[0][i]=x[i];
for(;;)
{
m++;
e=0;
for(i=0;i<n;i++)
{
double s=f[i];
for(k=0;k<n;k++)
s=s+L[i][k]*xm[m-1][k];
if(s>=-bound&&s<=bound)
xm[m][i]=s;
else
return -2;
e=max(fabs(xm[m][i]-xm[m-1][i]),e);
}
/*printf("x%d=",m);
for(i=0;i<n;i++)
printf("%.10f ",xm[m][i]);
printf("\n");*/
if(e<TOL||m>MAXN)
break;
}
if(m<=MAXN)
{
for(i=0;i<n;i++)
x[i]=xm[m][i];
return m;
}
else
return 0;
}
int Gauss_Seidel ( int n, double a[][MAX_SIZE], double b[], double x[], double TOL, int MAXN )
{
double L[MAX_SIZE][MAX_SIZE],xm[MAX_length][MAX_SIZE],f[MAX_SIZE],aa[MAX_SIZE][MAX_SIZE];
double e;
int i,k,m;
for(i=0;i<n;i++)
for(k=0;k<n;k++)
aa[i][k]=a[i][k];
for(k=0;k<n;k++)
f[k]=b[k];
if(maix(aa,f,L,n))
return -1;
m=0;
for(i=0;i<n;i++)
xm[0][i]=x[i];
for(;;)
{
m++;
e=0;
for(i=0;i<n;i++)
{
double s=f[i];
for(k=0;k<n;k++)
if(k<i)
s=s+L[i][k]*xm[m][k];
else
s=s+L[i][k]*xm[m-1][k];
if(s>=-bound&&s<=bound)
xm[m][i]=s;
else
return -2;
e=max(fabs(xm[m][i]-xm[m-1][i]),e);
}
/*printf("x%d=",m);
for(i=0;i<n;i++)
printf("%.10f ",xm[m][i]);
printf("\n");
/*printf("e=%.8f\n",e);*/
if(e<TOL||m>MAXN)
break;
}
if(m<=MAXN)
{
for(i=0;i<n;i++)
x[i]=xm[m][i];
return m;
}
else
return 0;
}
int main()
{
int n, MAXN, i, j, k;
double a[MAX_SIZE][MAX_SIZE], b[MAX_SIZE], x[MAX_SIZE];
double TOL;
while ( scanf("%d", &n) != EOF ) { /* 读取裁判测试用例 */
for ( i=0; i<n; i++ ) {
for ( j=0; j<n; j++ )
scanf("%lf", &a[i][j]);
scanf("%lf", &b[i]);
}
scanf("%lf %d", &TOL, &MAXN);
/*Jacobi( int n, double a[][MAX_SIZE], double b[], double x[], double TOL, int MAXN )*/
/* 输出雅可比算法的结果 */
printf("Result of Jacobi method:\n");
for ( i=0; i<n; i++ )
x[i] = 0.0;
k = Jacobi( n, a, b, x, TOL, MAXN );
switch ( k ) {
case -2:
printf("No convergence.\n");
break;
case -1:
printf("Matrix has a zero column. No unique solution exists.\n");
break;
case 0:
printf("Maximum number of iterations exceeded.\n");
break;
default:
printf("no_iteration = %d\n", k);
for ( j=0; j<n; j++ )
printf("%.8lf\n", x[j]);
break;
}
/* 输出高斯-塞德尔算法的结果 */
printf("Result of Gauss-Seidel method:\n");
for ( i=0; i<n; i++ )
x[i] = 0.0;
k = Gauss_Seidel( n, a, b, x, TOL, MAXN );
switch ( k ) {
case -2:
printf("No convergence.\n");
break;
case -1:
printf("Matrix has a zero column. No unique solution exists.\n");
break;
case 0:
printf("Maximum number of iterations exceeded.\n");
break;
default:
printf("no_iteration = %d\n", k);
for ( j=0; j<n; j++ )
printf("%.8lf\n", x[j]);
break;
}
printf("\n");
}
return 0;
}