数值分析实验报告
一、实验3.1
题目:
考虑线性方程组,,编制一个能自动选取主元,又能手动选取主元的求解线性代数方程组的Gauss消去过程。
(1)取矩阵,则方程有解。取计算矩阵的条件数。分别用顺序Gauss消元、列主元Gauss消元和完全选主元Gauss消元方法求解,结果如何?
(2)现选择程序中手动选取主元的功能,每步消去过程都选取模最小或按模尽可能小的元素作为主元进行消元,观察并记录计算结果,若每步消去过程总选取按模最大的元素作为主元,结果又如何?分析实验的结果。
(3)取矩阵阶数n=20或者更大,重复上述实验过程,观察记录并分析不同的问题及消去过程中选择不同的主元时计算结果的差异,说明主元素的选取在消去过程中的作用。
(4)选取其他你感兴趣的问题或者随机生成的矩阵,计算其条件数,重复上述实验,观察记录并分析实验的结果。
1.算法介绍
首先,分析各种算法消去过程的计算公式,顺序高斯消去法:
第k步消去中,设增广矩阵中的元素(若等于零则可以判定系数矩阵为奇异矩阵,停止计算),则对k行以下各行计算,分别用乘以增广矩阵的第行并加到第行,则可将增广矩阵中第列中以下的元素消为零;重复此方法,从第1步进行到第n-1步,则可以得到最终的增广矩阵,即;
列主元高斯消去法:
第k步消去中,在增广矩阵中的子方阵中,选取使得,当时,对中第行与第行交换,然后按照和顺序消去法相同的步骤进行。重复此方法,从第1步进行第n-1步,就可以得到最终的增广矩阵,即;
完全主元高斯消去法:
第k步消去中,在增广矩阵中对应的子方阵中,选取使得,若或,则对中第行与第行、第列与第列交换,然后按照和顺序消去法相同的步骤进行即可。重复此方法,从第1步进行到第n-1步,就可以得到最终的增广矩阵,即;
接下来,分析回代过程求解的公式,容易看出,对上述任一种消元法,均有以下计算公式:
2.实验程序的设计
一、输入实验要求及初始条件;
二、计算系数矩阵A的条件数及方程组的理论解;
三、对各不同方法编程计算,并输出最终计算结果。
3.计算结果及分析
(1)
先计算系数矩阵的条件数,结果如下,可知系数矩阵的条件数较大,故此问题属于病态问题,b或A的扰动都可能引起解的较大误差;
采用顺序高斯消去法,计算结果为:
最终解为x=(1.***,1.***,1.***,1.***,0.***,1.***,0.***,1.***,0.***,1.***)T
使用无穷范数衡量误差,得到=2.842***1e-14,可以发现,采用顺序高斯消元法求得的解与精确解之间误差较小。通过进一步观察,可以发现,按照顺序高斯消去法计算时,其选取的主元值和矩阵中其他元素大小相近,因此顺序高斯消去法方式并没有对结果造成特别大的影响。
若采用列主元高斯消元法,则结果为:
最终解为x=(1.***,1.***,1.***,1.***,1.***,1.***,1.***,1.***,1.***,1.***)T
同样使用无穷范数衡量误差,有=0;
若使用完全主元高斯消元法,则结果为
最终解x=(1.***,1.***,1.***,1.***,1.***,1.***,1.***,1.***,1.***,1.***)T
同样使用无穷范数衡量误差,有=0;
(2)
若每步都选取模最小或尽可能小的元素为主元,则计算结果为
最终解x=(1.***
1.***
1.***
1.***
0.***
1.***
0.***
1.***
0.***
1.***)T
使用无穷范数衡量误差,有为2.842***1e-14;而完全主元消去法的误差为=0。
从(1)和(2)的实验结果可以发现,列主元消去法和完全主元消去法都得到了精确解,而顺序高斯消去法和以模尽量小的元素为主元的消去法没有得到精确解。在后两种消去法中,由于程序计算时的舍入误差,对最终结果产生了一定的影响,但由于方程组的维度较低,并且元素之间相差不大,所以误差仍比较小。
为进一步分析,计算上述4种方法每步选取的主元数值,并列表进行比较,结果如下:
第n次消元
顺序
列主元
完全主元
模最小
6.***
6.***
4.***
4.***
4.***
4.***
4.***3333
4.***3333
4.***
4.***
4.***
4.***
4.0***063
4.0***063
4.***
4.***
4.0039***
4.0039***
4.***
0.0***469
0.0***469
4.***
从上表可以发现,对这个方程组而言,顺序高斯消去选取的主元恰好事模尽量小的元素,而由于列主元和完全主元选取的元素为8,与4在数量级上差别小,所以计算过程中的累积误差也较小,最终4种方法的输出结果均较为精确。
在这里,具体解释一下顺序法与模最小法的计算结果完全一致的原因。该矩阵在消元过程中,每次选取主元的一列只有两个非零元素,对角线上的元素为4左右,而其正下方的元素为8,该列其余位置的元素均为0。在这样的情况下,默认的主元也就是该列最小的主元,因此两种方法所得到的计算结果是一致的。
理论上说,完全高斯消去法的误差最小,其次是列主元高斯消去法,而选取模最小的元素作为主元时的误差最大,但是由于方程组的特殊性(元素相差不大并且维度不高),这个理论现象在这里并没有充分体现出来。
(3)
时,重复上述实验过程,各种方法的计算结果如下所示,在这里,仍采用无穷范数衡量绝对误差。
顺序高斯消去法
列主元高斯消去
完全主元高斯消去
选取模最小或尽可能小元素作为主元消去
X
1.***
1.***
1.***
1.***
0.***
1.***
0.***
1.***
0.***
1.***
0.***
1.***
0.***
1.***
0.***
1.***
0.***
1.***
0.***
1.***
1.***
1.***
1.***
1.***
0.***
1.***
0.***
1.***
0.***
1.***
0.***
1.***
0.***
1.***
0.***
1.***
0.***
1.***
0.***
1.***
2.***e-11
0
0
2.***e-11
可以看出,此时列主元和完全主元的计算结果仍为精确值,而顺序高斯消去和模尽可能小方法仍然产生了一定的误差,并且两者的误差一致。与n=10时候的误差比相比,n=20时的误差增长了大约1000倍,这是由于计算过程中舍入误差的不断累积所致。所以,如果进一步增加矩阵的维数,应该可以看出更明显的现象。
(4)
不同矩阵维度下的误差如下,在这里,为方便起见,选取2-条件数对不同维度的系数矩阵进行比较。
维度
条件数
顺序消去
列主元
完全主元
模尽量小
1.7e+3
2.84e-14
0
0
2.84e-14
1.8e+6
2.91e-11
0
0
2.91e-11
5.7e+7
9.31e-10
0
0
9.31e-10
1.8e+9
2.98e-08
0
0
2.98e-08
1.9e+12
3.05e-05
0
0
3.05e-05
3.8e+16
3.28e+04
3.88e-12
3.88e-12
3.28e+04
8.5e+16
3.52e+13
4.2e-3
4.2e-3
3.52e+13
从上表可以看出,随着维度的增加,不同方法对计算误差的影响逐渐体现,并且增长较快,这是由于舍入误差逐步累计而造成的。不过,方法二与方法三在维度小于40的情况下都得到了精确解,这两种方法的累计误差远比方法一和方法四慢;同样地,出于与前面相同的原因,方法一与方法四的计算结果保持一致,方法二与方法三的计算结果保持一致。
4.结论
本文矩阵中的元素差别不大,模最大和模最小的元素并没有数量级上的差异,因此,不同的主元选取方式对计算结果的影响在维度较低的情况下并不明显,四种方法都足够精确。
对比四种方法,可以发现采用列主元高斯消去或者完全主元高斯消去法,可以尽量抑制误差,算法最为精确。不过,对于低阶的矩阵来说,四种方法求解出来的结果误差均较小。
另外,由于完全选主元方法在选主元的过程中计算量较大,而且可以发现列主元法已经可以达到很高的精确程度,因而在实际计算中可以选用列主元法进行计算。
附录:程序代码
clear
clc;
format
long;
%方法选择
n=input('矩阵A阶数:n=');
disp('选取求解方式');
disp('1
顺序Gauss消元法,2
列主元Gauss消元法,3
完全选主元Gauss消元法,4
模最小或近可能小的元素作为主元');
a=input('求解方式序号:');
%赋值A和b
A=zeros(n,n);
b=zeros(n,1);
for
i=1:n
A(i,i)=6;
if
i>1
A(i,i-1)=8;
end
if
i A(i,i+1)=1; end end for i=1:n for j=1:n b(i)=b(i)+A(i,j); end end disp('给定系数矩阵为:'); A disp('右端向量为:'); b %求条件数及理论解 disp('线性方程组的精确解:'); X=(A\b)' fprintf('矩阵A的1-条件数: %f \n',cond(A,1)); fprintf('矩阵A的2-条件数: %f \n',cond(A)); fprintf('矩阵A的无穷-条件数: %f \n',cond(A,inf)); %顺序Gauss消元法 if a==1 A1=A;b1=b; for k=1:n if A1(k,k)==0 disp('主元为零,顺序Gauss消元法无法进行'); break end fprintf('第%d次消元所选取的主元:%g\n',k,A1(k,k)) %disp('此次消元后系数矩阵为:'); %A1 for p=k+1:n l=A1(p,k)/A1(k,k); A1(p,k:n)=A1(p,k:n)-l*A1(k,k:n); b1(p)=b1(p)-l*b1(k); end end x1(n)=b1(n)/A1(n,n); for k=n-1:-1:1 for w=k+1:n b1(k)=b1(k)-A1(k,w)*x1(w); end x1(k)=b1(k)/A1(k,k); end disp('顺序Gauss消元法解为:'); disp(x1); disp('所求解与精确解之差的无穷-范数为'); norm(x1-X,inf) end %列主元Gauss消元法 if a==2 A2=A;b2=b; for k=1:n [max_i,max_j]=find(A2(:,k)==max(abs(A2(k:n,k)))); if max_i~=k A2_change=A2(k,:); A2(k,:)=A2(max_i,:); A2(max_i,:)=A2_change; b2_change=b2(k); b2(k)=b2(max_i); b2(max_i)=b2_change; end if A2(k,k)==0 disp('主元为零,列主元Gauss消元法无法进行'); break end fprintf('第%d次消元所选取的主元:%g\n',k,A2(k,k)) %disp('此次消元后系数矩阵为:'); %A2 for p=k+1:n l=A2(p,k)/A2(k,k); A2(p,k:n)=A2(p,k:n)-l*A2(k,k:n); b2(p)=b2(p)-l*b2(k); end end x2(n)=b2(n)/A2(n,n); for k=n-1:-1:1 for w=k+1:n b2(k)=b2(k)-A2(k,w)*x2(w); end x2(k)=b2(k)/A2(k,k); end disp('列主元Gauss消元法解为:'); disp(x2); disp('所求解与精确解之差的无穷-范数为'); norm(x2-X,inf) end %完全选主元Gauss消元法 if a==3 A3=A;b3=b; for k=1:n VV=eye(n); [max_i,max_j]=find(A3(k:n,k:n)==max(max(abs(A3(k:n,k:n))))); if numel(max_i)==0 [max_i,max_j]=find(A3(k:n,k:n)==-max(max(abs(A3(k:n,k:n))))); end W=eye(n); W(max_i(1)+k-1,max_i(1)+k-1)=0; W(k,k)=0; W(max_i(1)+k-1,k)=1; W(k,max_i(1)+k-1)=1; V=eye(n); V(k,k)=0; V(max_j(1)+k-1,max_j(1)+k-1)=0; V(k,max_j(1)+k-1)=1; V(max_j(1)+k-1,k)=1; A3=W*A3*V; b3=W*b3; VV=VV*V; if A3(k,k)==0 disp('主元为零,完全选主元Gauss消元法无法进行'); break end fprintf('第%d次消元所选取的主元:%g\n',k,A3(k,k)) %disp('此次消元后系数矩阵为:'); %A3 for p=k+1:n l=A3(p,k)/A3(k,k); A3(p,k:n)=A3(p,k:n)-l*A3(k,k:n); b3(p)=b3(p)-l*b3(k); end end x3(n)=b3(n)/A3(n,n); for k=n-1:-1:1 for w=k+1:n b3(k)=b3(k)-A3(k,w)*x3(w); end x3(k)=b3(k)/A3(k,k); end disp('完全选主元Gauss消元法解为:'); disp(x3); disp('所求解与精确解之差的无穷-范数为'); norm(x3-X,inf) end %模最小或近可能小的元素作为主元 if a==4 A4=A;b4=b; for k=1:n AA=A4; AA(AA==0)=NaN; [min_i,j]=find(AA(k:n,k)==min(abs(AA(k:n,k)))); if numel(min_i)==0 [min_i,j]=find(AA(k:n,k)==-min(abs(AA(k:n,k:n)))); end W=eye(n); W(min_i(1)+k-1,min_i(1)+k-1)=0; W(k,k)=0; W(min_i(1)+k-1,k)=1; W(k,min_i(1)+k-1)=1; A4=W*A4; b4=W*b4; if A4(k,k)==0 disp('主元为零,模最小Gauss消元法无法进行'); break end fprintf('第%d次消元所选取的主元:%g\n',k,A4(k,k)) %A4 for p=k+1:n l=A4(p,k)/A4(k,k); A4(p,k:n)=A4(p,k:n)-l*A4(k,k:n); b4(p)=b4(p)-l*b4(k); end end x4(n)=b4(n)/A4(n,n); for k=n-1:-1:1 for w=k+1:n b4(k)=b4(k)-A4(k,w)*x4(w); end x4(k)=b4(k)/A4(k,k); end disp('模最小Gauss消元法解为:'); disp(x4); disp('所求解与精确解之差的无穷-范数为'); norm(x4-X,inf) end 二、实验3.3 题目: 考虑方程组的解,其中系数矩阵H为Hilbert矩阵: 这是一个著名的病态问题。通过首先给定解(例如取为各个分量均为1)再计算出右端的办法给出确定的问题。 (1)选择问题的维数为6,分别用Gauss消去法(即LU分解)、J迭代法、GS迭代法和SOR迭代法求解方程组,其各自的结果如何?将计算结果与问题的解比较,结论如何。 (2)逐步增大问题的维数,仍用上述的方法来解它们,计算的结果如何?计算的结果说明的什么? (3)讨论病态问题求解的算法。 1.算法设计 对任意线性方程组,分析各种方法的计算公式如下,(1)Gauss消去法: 首先对系数矩阵进行LU分解,有,则原方程转化为,令,则原方程可以分为两步回代求解: 具体方法这里不再赘述。 (2)J迭代法: 首先分解,再构造迭代矩阵,其中,进行迭代计算,直到误差满足要求。 (3)GS迭代法: 首先分解,再构造迭代矩阵,其中,进行迭代计算,直到误差满足要求。 (4)SOR迭代法: 首先分解,再构造迭代矩阵,其中,进行迭代计算,直到误差满足要求。 2.实验过程 一、根据维度n确定矩阵H的各个元素和b的各个分量值; 二、选择计算方法(Gauss消去法,J迭代法,GS迭代法,SOR迭代法),对迭代法设定初值,此外SOR方法还需要设定松弛因子; 三、进行计算,直至满足误差要求(对迭代法,设定相邻两次迭代结果之差的无穷范数小于0.0001;
3.计算结果及分析
(1)时,问题可以具体定义为
计算结果如下,Gauss消去法
第1次消元所选取的主元是:1
第2次消元所选取的主元是:0.0833333
第3次消元所选取的主元是:0.00555556
第4次消元所选取的主元是:0.000357143
第5次消元所选取的主元是:2.26757e-05
第6次消元所选取的主元是:1.43155e-06
解得X=(0.***
1.***
0.***
1.***
0.***
1.***)T
使用无穷范数衡量误差,可得=4.***e-10;
J迭代法
设定迭代初值为零,计算得到
J法的迭代矩阵B的谱半径为4.30853>1,所以J法不收敛;
GS迭代法
设定迭代初值为零,计算得到GS法的迭代矩阵G的谱半径为:0.999998<1,故GS法收敛,经过541次迭代计算后,结果为X=(1.001***6
0.***
0.***
1.***
1.***
0.***)T
使用无穷范数衡量误差,有=0.***;
SOR迭代法
设定迭代初值为零向量,并设定,计算得到SOR法迭代矩阵谱半径为0.***,经过100次迭代后的计算结果为
X=(1.***
0.***
1.03***59
1.06***81
1.***
0.9***527)T;
使用无穷范数衡量误差,有=0.***;
对SOR方法,可变,改变值,计算结果可以列表如下
迭代次数
迭代矩阵的谱半径
0.***
0.***
0.***
0.***
X
1.***
0.***
1.01***40
1.***
1.0***681
0.***
1.***
0.***
1.***
1.***
1.***
0.***
1.***
0.***
1.***
1.***
0.***
0.***
1.05***66
0.***
1.***
0.***
1.***
0.***
0.***
0.***
0.***
0.***
可以发现,松弛因子的取值对迭代速度造成了不同的影响,上述四种方法中,松弛因子=0.5时,收敛相对较快。
综上,四种算法的结果列表如下:
算法
Gauss消去法
Jacobi法
GS法
SOR法(取)
迭代次数
--
不收敛
541
迭代矩阵的谱半径
--
4.30853
0.999998
0.***
X
0.***
1.***
0.***
1.***
0.***
1.***
--
1.001***6
0.***
0.***
1.***
1.***
0.***
1.***
0.***
1.03***59
1.06***81
1.***
0.9***527
4.***e-10
--
0.***
0.***
计算可得,矩阵H的条件数为>>1,所以这是一个病态问题。由上表可以看出,四种方法的求解都存在一定的误差。下面分析误差的来源:
LU分解方法的误差存在主要是由于Hilbert矩阵各元素由分数形式转换为小数形式时,不能除尽情况下会出现舍入误差,在进行LU分解时也存在这个问题,所以最后得到的结果不是方程的精确解,但结果显示该方法的误差非常小;
Jacobi迭代矩阵的谱半径为4.30853,故此迭代法不收敛;
GS迭代法在迭代次数为541次时得到了方程的近似解,其误差约为0.05,比较大。GS迭代矩阵的谱半径为0.999998,很接近1,所以GS迭代法收敛速度较慢;
SOR迭代法在迭代次数为100次时误差约为0.08,误差较大。SOR迭代矩阵的谱半径为0.999999,也很接近1,所以时SOR迭代法收敛速度不是很快,但是相比于GS法,在迭代速度方面已经有了明显的提高;另外,对不同的,SOR方法的迭代速度会相应有变化,如果选用最佳松弛因子,可以实现更快的收敛;
(2)
考虑不同维度的情况,时,算法
Gauss消去
J法
GS法
SOR法(w=0.5)
计算结果
0.***
1.***
0.***
1.***
0.***
1.***
0.***
1.***
--
0.***
1.***
0.***
1.***
1.***
1.***
0.9968***
0.***
1.***
0.9397***
0.***
1.***
1.***
1.***
0.***
0.***
迭代次数
--
--
356
谱半径
--
6.04213
0.***
--
时,算法
Gauss消去法
Jacobi法
GS法
SOR法(w=0.5)
计算结果
0.***
1.***
0.***
1.000***1
0.***
1.***
0.***
1.***
0.***
1.***
0.***
--
0.***
1.***
0.***
0.***
0.***
1.02***91
1.***
1.***
1.***
0.***
0.947***7
1.0***572
0.***
0.***
0.***
1.***
1.***
1.***
1.***
0.***
0.***
0.***
迭代次数
--
--
1019
谱半径
--
8.64964
0.***
--
时
算法
Gauss消去法
Jacobi法
GS法
SOR法(w=0.5)
计算结果
0.***
1.***
0.***
0.***
1.***
0.***
2.***
-2.***
7.***
-7.***
7.***
-1.***
0.***
1.***
0.***
--
不收敛
1.***
1.***
0.907***9
0.***
0.***
1.***
1.09***64
1.***
1.***
1.***
1.0385***
0.***
0.942***3
0.***
0.***
迭代次数
--
--
262
谱半径
--
6.04213
>1
1.***
8.***
--
--
0.***
分析以上结果可以发现,随着n值的增加,Gauss消去法误差逐渐增大,而且误差增大的速度很快,在维数小于等于10情况下,Gauss消去法得到的结果误差较小;但当维数达到15时,计算结果误差已经达到精确解的很多倍;
J法迭代不收敛,无论n如何取值,其谱半径始终大于1,因而J法不收敛,所以J迭代法不能用于Hilbert矩阵的求解;
对于GS迭代法和SOR迭代法,两种方法均收敛,GS迭代法是SOR迭代法松弛因子取值为1的特例,SOR方法受到取值的影响,会有不同的收敛情况。可以得出GS迭代矩阵的谱半径小于1但是很接近1,收敛速度很慢。虽然随着维数的增大,所需迭代的次数逐渐减少,但是当维数达到15的时候,GS法已经不再收敛。因此可以得出结论,GS迭代方法在Hilbert矩阵维数较低时,能够在一定程度上满足迭代求解的需求,不过迭代的速度很慢。另外,随着矩阵维数的增加,SOR法的误差水平基本稳定,而且误差在可以接受的范围之内。
经过比较可以得出结论,如果求解较低维度的Hibert矩阵问题,Gauss消去法、GS迭代法和SOR迭代法均可使用,且Gauss消去法的结果精确度较高;如果需要求解较高维度的Hibert矩阵问题,只有采用SOR迭代法。
(3)
系数矩阵的条件数较大时,为病态方程。由实验可知,Gauss法在解上述方程时,结果存在很大的误差。而对于收敛的迭代法,可以通过选取最优松弛因子的方法来求解,虽然迭代次数相对较多,但是结果较为精确。
总体来看,对于一般病态方程组的求解,可以采用以下方式:
1.低维度下采用Gauss消去法直接求解是可行的;
Jacobi迭代方法不适宜于求解病态问题;
GS迭代方法可以解决维数较低的病态问题,但其谱半径非常趋近于1,导致迭代算法收敛速度很慢,维数较大的时候,GS法也不再收敛;
SOR方法较适合于求解病态问题,特别是矩阵维数较高的时候,其优势更为明显。
2.采用高精度的运算,如选用双倍或更多倍字长的运算,可以提高收敛速度;
3.可以对原方程组作某些预处理,从而有效降低系数矩阵的条件数。
4.实验结论
(1)对Hibert矩阵问题,其条件数会随着维度的增加迅速增加,病态性会越来越明显;在维度较低的时候,Gauss消去法、GS迭代法和SOR迭代法均可使用,且可以优先使用Gauss消去法;如果需要求解较高维度的Hibert矩阵问题,只有SOR迭代法能够求解。
(2)SOR方法比较适合于求解病态问题,特别是矩阵维数较高的时候,其优点更为明显。从本次实验可以看出,随着矩阵维数的增大,SOR方法所需的迭代次数减少,而且误差基本稳定,是解决病态问题的适宜方法。
附录:程序代码
clear
all
clc;
format
long;
%矩阵赋值
n=input('矩阵H的阶数:n=');
for
i=1:n
for
j=1:n
H(i,j)=1/(i+j-1);
end
end
b=H*ones(n,1);
disp('H矩阵为:');
H
disp('向量b:');
b
%方法选择
disp('选取求解方式');
disp('1
Gauss消去法,2
J迭代法,3
GS迭代法,4
SOR迭代法');
a=input('求解方式序号:');
%Gauss消去法
if
a==1;
H1=H;b1=b;
for
k=1:n
if
H1(k,k)==0
disp('主元为零,Gauss消去法无法进行');
break
end
fprintf('第%d次消元所选取的主元是:%g\n',k,H1(k,k))
for
p=k+1:n
m5=-H1(p,k)/H1(k,k);
H1(p,k:n)=H1(p,k:n)+m5*H1(k,k:n);
b1(p)=b1(p)+m5*b1(k);
end
end
x1(n)=b1(n)/H1(n,n);
for
k=n-1:-1:1
for
v=k+1:n
b1(k)=b1(k)-H1(k,v)*x1(v);
end
x1(k)=b1(k)/H1(k,k);
end
disp('Gauss消去法解为:');
disp(x1);
disp('解与精确解之差的无穷范数');
norm((x1-a),inf)
end
D=diag(diag(H));
L=-tril(H,-1);
U=-triu(H,1);
%J迭代法
if
a==2;
%给定初始x0
ini=input('初始值设定:x0=');
x0(:,1)=ini*diag(ones(n));
disp('初始解向量为:');
x0
xj(:,1)=x0(:,1);
B=(D^(-1))*(L+U);
f=(D^(-1))*b;
fprintf('(J法B矩阵谱半径为:%g\n',vrho(B));
if
vrho(B)<1;
for
m2=1:5000
xj(:,m2+1)=B*xj(:,m2)+fj;
if
norm((xj(:,m2+1)-xj(:,m2)),inf)<0.0001
break
end
end
disp('J法计算结果为:');
xj(:,m2+1)
disp('解与精确解之差的无穷范数');
norm((xj(:,m2+1)-diag(ones(n))),inf)
disp('J迭代法迭代次数:');
m2
else
disp('由于B矩阵谱半径大于1,因而J法不收敛');
end
end
%GS迭代法
if
a==3;
%给定初始x0
ini=input('初始值设定:x0=');
x0(:,1)=ini*diag(ones(n));
disp('初始解向量为:');
x0
xG(:,1)=x0(:,1);
G=inv(D-L)*U;
fG=inv(D-L)*b;
fprintf('GS法G矩阵谱半径为:%g\n',vrho(G));
if
vrho(G)<1
for
m3=1:5000
xG(:,m3+1)=G*xG(:,m3)+fG;
if
norm((xG(:,m3+1)-xG(:,m3)),inf)<0.0001
break;
end
end
disp('GS迭代法计算结果:');
xG(:,m3+1)
disp('解与精确解之差的无穷范数');
norm((xG(:,m3+1)-diag(ones(n))),inf)
disp('GS迭代法迭代次数:');
m3
else
disp('由于G矩阵谱半径大于1,因而GS法不收敛');
end
end
%SOR迭代法
if
a==4;
%给定初始x0
ini=input('初始值设定:x0=');
x0(:,1)=ini*diag(ones(n));
disp('初始解向量为:');
x0
A=H;
for
i=1:n
b(i)=sum(A(i,:));
end
x_star=ones(n,1);
format
long
w=input('松弛因子:w=');
Lw=inv(D-w*L)*((1-w)*D+w*U);
f=w*inv(D-w*L)*b;
disp('迭代矩阵的谱半径:')
p=vrho(Lw)
time_max=100;%迭代次数
x=zeros(n,1);%迭代初值
for
i=1:time_max
x=Lw*x+f;
end
disp('SOR迭代法得到的解为');
x
disp('解与精确解之差的无穷范数');
norm((x_star-x),inf)
end
pause
三、实验4.1
题目:
对牛顿法和拟牛顿法。进行非线性方程组的数值求解
(1)用上述两种方法,分别计算下面的两个例子。在达到精度相同的前提下,比较其迭代次数、CPU时间等。
(2)取其他初值,结果又如何?反复选取不同的初值,比较其结果。
(3)总结归纳你的实验结果,试说明各种方法适用的问题。
1.算法设计
对需要求解的非线性方程组而言,牛顿法和拟牛顿法的迭代公式如下,(1)牛顿法:
牛顿法为单步迭代法,需要取一个初值。
(2)拟牛顿法:(Broyden秩1法)
其中,拟牛顿法不需要求解的导数,因此节省了大量的运算时间,但需要给定矩阵的初值,取为。
2.实验过程
一、输入初值;
二、根据误差要求,按公式进行迭代计算;
三、输出数据;
3.计算结果及分析
(1)首先求解方程组(1),在这里,设定精度要求为,方法
牛顿法
拟牛顿法
初始值
计算结果X
x1
0.***
0.***
x2
1.***
1.0852***
x3
0.***
0.***
迭代次数
CPU计算时间/s
3.777815
2.739349
可以看出,在初始值相同情况下,牛顿法和拟牛顿法在达到同样计算精度情况下得到的结果基本相同,但牛顿法的迭代次数明显要少一些,但是,由于每次迭代都需要求解矩阵的逆,所以牛顿法每次迭代的CPU计算时间更长。
之后求解方程组(2),同样设定精度要求为
方法
牛顿法
拟牛顿法
初始值
计算结果X
x1
0.***
0.***
x2
0.***
0.***
x3
-0.***
-0.***
迭代次数
CPU计算时间/s
2.722437
3.920195
同样地,可以看出,在初始值相同情况下,牛顿法和拟牛顿法在达到同样计算精度情况下得到的结果是基本相同的,但牛顿法的迭代次数明显要少,但同样的,由于每次迭代中有求解矩阵的逆的运算,牛顿法每次迭代的CPU计算时间较长。
(2)对方程组(1),取其他初值,计算结果列表如下,同样设定精度要求为
初始值
方法
牛顿法
拟牛顿法
计算结果
0.***
1.***
0.***
9.21***94
-5.***
18.1***205
迭代次数
CPU计算时间/s
3.907164
4.818019
计算结果
0.***
1.***
0.***
9.21***91
-5.***
18.1***807
迭代次数
2735
CPU计算时间/s
8.127286
5.626023
计算结果
0.***
1.***
0.***
0.***
1.0852***
0.***
迭代次数
CPU计算时间/s
3.777815
2.739349
计算结果
0.***
1.***
0.***
0.***
1.***
0.***
迭代次数
188
CPU计算时间/s
3.835697
2.879070
计算结果
9.21***22
-5.***
18.1***605
Matlab警告矩阵接近奇异值,程序进入长期循环计算中
迭代次数
--
CPU计算时间/s
4.033868
--
计算结果
0.***
1.***
0.***
Matlab警告矩阵接近奇异值,程序进入长期循环计算中
迭代次数
--
CPU计算时间/s
12.243263
--
从上表可以发现,方程组(1)存在另一个在(9.2,-5.6,18.1)T附近的不动点,初值的选取会直接影响到牛顿法和拟牛顿法最后的收敛点。
总的来说,设定的初值离不动点越远,需要的迭代次数越多,因而初始值的选取非常重要,合适的初值可以更快地收敛,如果初始值偏离精确解较远,会出现迭代次数增加直至无法收敛的情况;
由于拟牛顿法是一种近似方法,拟牛顿法需要的的迭代次数明显更多,而且收敛情况不如牛顿法好(初值不够接近时,甚至会出现奇异矩阵的情况),但由于牛顿法的求解比较复杂,计算时间较长;
同样的,对方程组(2),取其他初值,计算结果列表如下,同样设定精度要求为
初始值
方法
牛顿法
拟牛顿法
计算结果
0.***
0.***
-0.***
0.***
0.***
-0.***
迭代次数
CPU计算时间/s
2.722437
3.920195
计算结果
0.***
0.***
-0.***
0.***
-0.***
76.***
迭代次数
CPU计算时间/s
5.047111
5.619752
计算结果
0.***
0.***
-0.***
1.0e+02
*
-0.***
-0.000***6
1.754***3
迭代次数
CPU计算时间/s
3.540668
3.387829
计算结果
0.***
0.***
-0.***
1.0e+04
*
0.***
-0.***
1.***
迭代次数
CPU计算时间/s
2.200571
2.640901
计算结果
0.***
0.***
-0.***
矩阵为奇异值,无法输出准确结果
迭代次数
--
CPU计算时间/s
1.719072
--
计算结果
0.***
0.***
-0.***
矩阵为奇异值,无法输出准确结果
迭代次数
149
--
CPU计算时间/s
2.797116
--
计算结果
矩阵为奇异值,无法输出准确结果
矩阵为奇异值,无法输出准确结果
迭代次数
--
--
CPU计算时间/s
--
--
在这里,与前文类似的发现不再赘述。
从这里看出,牛顿法可以在更大的区间上实现压缩映射原理,可以在更大的范围上选取初值并最终收敛到精确解附近;
在初始值较接近于不动点时,牛顿法和拟牛顿法计算所得到的结果是基本相同的,虽然迭代次数有所差别,但计算总的所需时间相近。
(3)
牛顿法在迭代过程中用到了矩阵的求逆,其迭代收敛的充分条件是迭代满足区间上的映内性,对于矩阵的求逆过程比较简单,所以在较大区间内满足映内性的问题适合应用牛顿法进行计算。一般而言,对于函数单调或者具有单值特性的函数适合应用牛顿法,其对初始值敏感程度较低,算法具有很好的收敛性。
另外,需要说明的是,每次计算给出的CPU时间与计算机当时的运行状态有关,同时,不同代码的运行时间也不一定一致,所以这个数据并不具有很大的参考价值。
4.实验结论
对牛顿法和拟牛顿法,都存在初始值越接近精确解,所需的迭代次数越小的现象;
在应用上,牛顿法和拟牛顿法各有优势。就迭代次数来说,牛顿法由于更加精确,所需的迭代次数更少;但就单次迭代来说,牛顿法由于计算步骤更多,且计算更加复杂,因而每次迭代所需的时间更长,而拟牛顿法由于采用了简化的近似公式,其每次迭代更加迅速。当非线性方程组求逆过程比较简单时,如方程组1的情况时,拟牛顿法不具有明显的优势;而当非线性方程组求逆过程比较复杂时,如方程组2的情况,拟牛顿法就可以体现出优势,虽然循环次数有所增加,但是CPU耗时反而更少。
另外,就方程组压缩映射区间来说,一般而言,对于在区间内函数呈现单调或者具有单值特性的函数适合应用牛顿法,其对初始值敏感程度较低,使算法具有很好的收敛性;而拟牛顿法由于不需要在迭代过程中对矩阵求逆,而是利用差商替代了对矩阵的求导,所以即使初始误差较大时,其倒数矩阵与差商偏差也较小,所以对初始值的敏感程度较小。
附录:程序代码
%方程1,牛顿法
tic;
format
long;
%%初值
disp('请输入初值');
a=input('第1个分量为:');
b=input('第2个分量为:');
c=input('第3个分量为:');
disp('所选定初值为');
x=[a;b;c]
%%误差要求
E=0.0001;
%%迭代
i=0;
e=2*E;
while
e>E
F=[12*x(1)-x(2)^2-4*x(3)-7;x(1)^2+10*x(2)-x(3)-11;x(2)^3+10*x(3)-8];
f=[12,-2*x(2),-4;2*x(1),10,-1;0,3*x(2)^2,10];
det_x=((f)^(-1))*(-F);
x=x+det_x;
e=max(norm(det_x));
i=i+1;
end
disp('迭代次数');
i
disp('迭代次数');
x
toc;
%方程1,拟牛顿法
tic;
format
long;
%%初值
%%初值
disp('请输入初值');
a=input('第1个分量为:');
b=input('第2个分量为:');
c=input('第3个分量为:');
disp('所选定初值为');
x0=[a;b;c]
%%误差要求
E=0.0001;
%%迭代
i=0;
e=2*E;
A0=eye(3);
while
e>E
F0=[12*x0(1)-x0(2)^2-4*x0(3)-7;x0(1)^2+10*x0(2)-x0(3)-11;x0(2)^3+10*x0(3)-8];
x1=x0-A0^(-1)*F0;
s=x1-x0;
F1=[12*x1(1)-x1(2)^2-4*x1(3)-7;x1(1)^2+10*x1(2)-x1(3)-11;x1(2)^3+10*x1(3)-8];
y=F1-F0;
A1=A0+(y-A0*s)*s'/(s'*s);
x0=x1;
A0=A1;
e=max(norm(s));
i=i+1;
end
disp('迭代次数');
i
disp('迭代次数');
x0
toc;
%方程2,牛顿法
tic;
format
long;
%%初值
disp('请输入初值');
a=input('第1个分量为:');
b=input('第2个分量为:');
c=input('第3个分量为:');
disp('所选定初值为');
x=[a;b;c]
%%误差要求
E=0.0001;
%%迭代
i=0;
e=2*E;
while
e>E
F=[3*x(1)-cos(x(2)*x(3))-0.5;x(1)^2-81*(x(2)+0.1)^2+sin(x(3))+1.06;exp(1)^(-x(1)*x(2))+20*x(3)+(10*pi-3)/3];
f=[3,x(3)*sin(x(2)*x(3)),x(2)*sin(x(2)*x(3));2*x(1),-162*x(2)-81/5,cos(x(3));-x(2)*exp(1)^(-x(1)*x(2)),-x(1)*exp(1)^(-x(1)*x(2)),20];
det_x=((f)^(-1))*(-F);
x=x+det_x;
e=max(norm(det_x));
i=i+1;
end
disp('迭代次数');
i
disp('迭代次数');
x
toc;
%方程2,拟牛顿法
tic;
format
long;
%%初值
%%初值
disp('请输入初值');
a=input('第1个分量为:');
b=input('第2个分量为:');
c=input('第3个分量为:');
disp('所选定初值为');
x0=[a;b;c]
%%误差要求
E=0.0001;
%%迭代
i=0;
e=2*E;
A0=eye(3);
while
e>E
F0=[3*x0(1)-cos(x0(2)*x0(3))-0.5;x0(1)^2-81*(x0(2)+0.1)^2+sin(x0(3))+1.06;exp(1)^(-x0(1)*x0(2))+20*x0(3)+(10*pi-3)/3];
x1=x0-A0^(-1)*F0;
s=x1-x0;
F1=[3*x1(1)-cos(x1(2)*x1(3))-0.5;x1(1)^2-81*(x1(2)+0.1)^2+sin(x1(3))+1.06;exp(1)^(-x1(1)*x1(2))+20*x1(3)+(10*pi-3)/3];
y=F1-F0;
A1=A0+(y-A0*s)*s'/(s'*s);
x0=x1;
A0=A1;
e=max(norm(s));
i=i+1;
end
disp('迭代次数');
i
disp('迭代次数');
x0
toc;