数值分析迭代法.docx
《数值分析迭代法.docx》由会员分享,可在线阅读,更多相关《数值分析迭代法.docx(26页珍藏版)》请在冰豆网上搜索。
数值分析迭代法
数值分析实验报告
(3)
学院:
信息学院
班级:
计算机0903班
姓名:
王明强
学号:
20092954
课题三线性方程组的迭代法
一、问题提出
1、设线性方程组
=
x
=(1,-1,0,1,2,0,3,1,-1,2)
2、设对称正定阵系数阵线方程组
=
x
=(1,-1,0,2,1,-1,0,2)
3、三对角形线性方程组
=
x
=(2,1,-3,0,1,-2,3,0,1,-1)
试分别选用Jacobi迭代法,Gauss-Seidol迭代法和SOR方法计算其解。
二、要求
1、体会迭代法求解线性方程组,并能与消去法做以比较;
2、分别对不同精度要求,如
由迭代次数体会该迭代法的收敛快慢;
3、对方程组2,3使用SOR方法时,选取松弛因子
=0.8,0.9,1,1.1,1.2等,试看对算法收敛性的影响,并能找出你所选用的松弛因子的最佳者;
4、给出各种算法的设计程序和计算结果。
三、目的和意义
1、通过上机计算体会迭代法求解线性方程组的特点,并能和消去法比较;
gauss消去法是一种规则化的加减消元法。
它的基本思想是:
通过逐次消元计算把需要求求解的线性方程转化成上三角形方程组,也就是把线性方程组的系数矩阵转化为上三角矩阵,从而使一般线性方程组求解转化为等价(同解)的上三角方程组的求解。
消去法是直接方法的一种。
优点:
对于简单的方程组可以很快得出结果,计算中如果没有舍入误差,在稳定的方程组中容易得到精确解,理论上可以求解任何可以求出解得方程组。
缺点:
数值有的时候不稳定(可采用列主元gauss消去法),既要消去,又要回代,算法实现起来比较复杂,不适用于大规模方程组。
迭代法是从某一取定的初始向量x(0)出发,按照一个适当的迭代公式,逐次计算出向量x
(1),x
(2),......,使得向量序列{x(k)}收敛于方程组的精确解,这样,对于适当大的k,可取x(k)作为方程组的近似解。
优点:
算法简单,程序易于实现,特别适用求解大型稀疏线性方程组。
缺点:
与直接方法不同,即使在计算过程中无舍入误差,迭代法也难获得精确解。
而且并不是所有方程组都适用我们学过的迭代法,对于这样的方程组,我们还必须自己构造一个收敛的迭代矩阵。
2、运用所学的迭代法算法,解决各类线性方程组,编出算法程序;
Jacobi迭代:
Y
N
Y
Gauss-Seidel迭代
Y
N
Y
SOR迭代
Y
N
Y
3、体会上机计算时,终止步骤
<
或k>(予给的迭代次数),对迭代法敛散性的意义;
对例子3做J迭代法
选择用以后的矩阵初始化,选择矩阵3。
精度为0.01。
初始向量为(0,0,0,0,0,0,0,0,0,0)T
用Jacobi迭代,验证精度问题。
迭代次数为9。
精度为0.001。
初始向量为(0,0,0,0,0,0,0,0,0,0)T
迭代次数为11。
精度为0.0001。
初始向量为(0,0,0,0,0,0,0,0,0,0)T
迭代次数为14。
答:
在精度越高的情况下迭代的次数也越高。
在使用同一个迭代法的时候收
敛速度是一样的,迭代次数越多,所得到的结果越接近精确解。
4、体会初始解x
,松弛因子的选取,对计算结果的影响。
答:
初始解要是接近精确解得时候收敛的比较快。
选取矩阵2,精度为0.001,最大迭代次数100000。
分别选取w=0.8,0.9,1,1.1,1.2。
由上面的结果可以看出,w逐渐增大的时候迭代次数在逐渐减少,w=1.2的时候收敛的最快,w=1.2是矩阵2的最优解。
选取矩阵3,精度为0.001,最大迭代次数100000。
分别选取w=0.8,0.9,1,1.1,1.2。
随着w增大,迭代次数先减小后增大,选取w=1.0为最优迭代。
答:
<
退出时,结果为收敛的结果,一般比较接近精确解,k>(予给的迭代次数)退出时,有可能迭代矩阵不收敛,或者还没有达到精度要求。
四、实验结果分析和心得
对于这次实验的,矩阵一不收敛,无论通过各种迭代法,都无法得到一个精确的解。
而且结果不是一个收敛的值,会出现无穷大和无穷小量。
矩阵二只有Gauss-Seidel和SOR方法收敛,但是通过迭代的时候无法得到老师所给出的精确解。
而是收敛到另一组向量,Jacobi迭代方法不收敛。
矩阵三各种方法均适用,而且都可以得到老师给出的精确解。
通过这次实验让我更深刻的了解到了各种迭代法的适用条件,同时也让我知道了,不是所有方程都能通过迭代法来求解。
而且迭代法是存在一定误差的,即使我们在做程序时,不考虑舍入误差,也是会产生一定的机器误差的。
但是迭代法对于我们来说也是非常有意义的,比如一些大的工程我们用一些基本的方法可能根本不能计算或者非常麻烦,这个时候要是能使用迭代法就会让问题简单化,给我们带来了极大的便利。
具体程序如下:
#include
#include
#include
#include
intn;//矩阵的维数
longN,k;//最大迭代次数,当前迭代次数
floate;//精度要求
floatw=0;//松弛因子
inta[10][10],b[10];//矩阵和右端项
floatx[10];//初始向量
voidinput()//初始化函数
{
inti,j;
system("cls");
printf("请输入矩阵维数(不大于10):
\n");
scanf("%d",&n);
printf("请输入矩阵A:
\n");
for(i=0;ifor(j=0;jscanf("%d",&a[i][j]);
printf("请输入右端项:
\n");
for(i=0;iscanf("%d",&b[i]);
printf("请输入初始向量:
\n");
for(i=0;iscanf("%f",&x[i]);
printf("请输入要求精度:
\n");
scanf("%f",&e);
printf("请输入最大迭代次数:
\n");
scanf("%ld",&N);
}
voidinit()
{
inti,j;
inta1[10][10]=
{4,2,-3,-1,2,1,0,0,0,0,
8,6,-5,-3,6,5,0,1,0,0,
4,2,-2,-1,3,2,-1,0,3,1,
0,-2,1,5,-1,3,-1,1,9,4,
-4,2,6,-1,6,7,-3,3,2,3,
8,6,-8,5,7,17,2,6,-3,5,
0,2,-1,3,-4,2,5,3,0,1,
16,10,-11,-9,17,34,2,-1,2,2,
4,6,2,-7,13,9,2,0,12,4,
0,0,-1,8,-3,-24,-8,6,3,-1};
intb1[10]=
{5,12,3,2,3,46,13,38,19,-21};
inta2[8][8]=
{4,2,-4,0,2,4,0,0,
2,2,-1,-2,1,3,2,0,
-4,-1,14,1,-8,-3,5,6,
0,-2,1,6,-1,-4,-3,3,
2,1,-8,-1,22,4,-10,-3,
4,3,-3,-4,4,11,1,-4,
0,2,5,-3,-10,1,14,2,
0,0,6,3,-3,-4,2,19};
intb2[8]=
{0,-6,20,23,9,-22,-15,45};
inta3[10][10]=
{4,-1,0,0,0,0,0,0,0,0,
-1,4,-1,0,0,0,0,0,0,0,
0,-1,4,-1,0,0,0,0,0,0,
0,0,-1,4,-1,0,0,0,0,0,
0,0,0,-1,4,-1,0,0,0,0,
0,0,0,0,-1,4,-1,0,0,0,
0,0,0,0,0,-1,4,-1,0,0,
0,0,0,0,0,0,-1,4,-1,0,
0,0,0,0,0,0,0,-1,4,-1,
0,0,0,0,0,0,0,0,-1,4};
intb3[10]=
{7,5,-13,2,6,-12,14,-4,5,-5};
system("cls");
printf("请输入要用例子中哪个矩阵初始化:
\n");
scanf("%d",&i);
switch(i)
{
case1:
n=10;
for(i=0;i{
for(j=0;ja[i][j]=a1[i][j];
b[i]=b1[i];
}
break;
case2:
n=8;
for(i=0;i{
for(j=0;ja[i][j]=a2[i][j];
b[i]=b2[i];
}
break;
case3:
n=10;
for(i=0;i{
for(j=0;ja[i][j]=a3[i][j];
b[i]=b3[i];
}
break;
default:
printf("输入错误\n");
break;
}
printf("请输入初始向量:
\n");
for(i=0;iscanf("%f",&x[i]);
printf("请输入要求精度:
\n");
scanf("%f",&e);
printf("请输入最大迭代次数:
\n");
scanf("%ld",&N);
}
voidoutput()//输出函数
{
inti;
system("cls");
if(w!
=0)printf("松弛因子为:
%f\n",w);
printf("迭代结果为:
\n");
for(i=0;iprintf("%f\t",x[i]);
printf("\n");
if(k>N)printf("超过最大迭代次数\n");
elseprintf("迭代次数为%d\n",k);
system("pause");
}
floatnorm(floaty[])//求向量的无穷范数
{
floatresult,temp;
inti;
result=fabs(x[0]-y[0]);
for(i=1;i{
temp=fabs(x[i]-y[i]);
if(result}
returnresult;
}
voidjacobi()//雅克比迭代
{
inti,j;
floaty[10],R,temp;//y[10]保存上一次迭代结果
system("cls");
for(k=1;k<=N;k++)
{
for(i=0;iy[i]=x[i];
for(i=0;i{
temp=0;
for(j=0;jtemp+=a[i][j]*y[j];
x[i]=y[i]+(b[i]-temp)/a[i][i];
}
R=norm(y);
if(R<=e)
{
output();
break;
}
}
if(k==N+1)
{
printf("超过最大迭代次数\n");
system("pause");
}
}
voidgauss_seidel()//高斯-塞德尔迭代
{
inti,j;
floaty[10],R,temp;//y[10]保存上一次迭代结果
system("cls");
for(k=1;k<=N;k++)
{
for(i=0;iy[i]=x[i];
for(i=0;i{
temp=0;
for(j=0;j
temp+=a[i][j]*x[j];
for(j=i;jtemp+=a[i][j]*y[j];
x[i]=y[i]+(b[i]-temp)/a[i][i];
}
R=norm(y);
if(R<=e)
{
output();
break;
}
}
if(k==N+1)
{
printf("超过最大迭代次数\n");
system("pause");
}
}
voidsor()//逐次超松弛迭代
{
inti,j;
floaty[10],R,temp;//y[10]保存上一次迭代结果
system("cls");
printf("请输入松弛因子:
\n");
scanf("%f",&w);
for(k=1;k<=N;k++)
{
for(i=0;iy[i]=x[i];
for(i=0;i{
temp=0;
for(j=0;j
temp+=a[i][j]*x[j];
for(j=i;jtemp+=a[i][j]*y[j];
x[i]=y[i]+w*(b[i]-temp)/a[i][i];
}
R=norm(y);
if(R<=e)
{
output();
break;
}
}
if(k==N+1)
{
printf("超过最大迭代次数\n");
system("pause");
}
}
voidmain()
{
inti;
do
{
system("cls");
printf("\t\t################################################\n");
printf("\t\t###########数值分析###########\n");
printf("\t\t##\n");
printf("\t\t#1.初始化矩阵和右端向量.#\n");
printf("\t\t##\n");
printf("\t\t#2.用例子矩阵和右端向量初始化.#\n");
printf("\t\t##\n");
printf("\t\t#3.Jacobi迭代.#\n");
printf("\t\t##\n");
printf("\t\t#4.Gauss-Seiled迭代.#\n");
printf("\t\t##\n");
printf("\t\t#5.逐次好松弛迭代(SOR).#\n");
printf("\t\t##\n");
printf("\t\t#6.输出结果和迭代次数.#\n");
printf("\t\t##\n");
printf("\t\t#0.退出程序.#\n");
printf("\t\t################################################\n");
printf("pleasechoosefrom0-5:
");
scanf("%d",&i);
switch(i)
{
case1:
input();break;
case2:
init();break;
case3:
jacobi();break;
case4:
gauss_seidel();break;
case5:
sor();break;
case6:
output();break;
case0:
exit
(1);break;
default:
break;
}
}while(i!
=0);
}