lckboy 发表于 2004-6-3 22:11

[原创]全主元Gauss-Jordan消元法(Blitz++库)

<P align=center><B><FONT size=6>全主元Gauss-Jordan消元法</FONT></B>
<P>
<P><B>
<P></B>
<P>
<P><B>
<P></B>
<P>
<P><B>
<P></B>
<P>
<P><FONT size=4>     Gauss-Jordan消元法是经典的线性方程组<B>A·X=b</B>求解方法,该方法的优点是稳定,而全主元法可能更加稳定,同时,它也存在着弱点——求解速度可能较慢。</FONT>
<P><FONT size=4></FONT></P>
<P><FONT size=4></FONT></P>
<P><FONT size=4></FONT>
<P><FONT size=4></FONT></P>
<P><FONT size=4></FONT></P>
<P><FONT size=4>     Gauss-Jordan消元法主要特点是通过交换任意的行列,<B>把矩阵A约化为单位矩阵,约化完成后,方程组右端项向量b即为解向量。</B>我们知道,选择绝对值最大的元素作为主元是很好的办法,所以,全主元法目的就是在一个大的范围里面寻找主元,以达到比较高的精度。</FONT>
<P><FONT size=4></FONT></P>
<P><FONT size=4></FONT></P>
<P><FONT size=4></FONT>
<P><FONT size=4></FONT></P>
<P><FONT size=4></FONT></P>
<P><FONT size=4>     下面,我使用Blitz++的Array库,编写全主元Gauss-Jordan消元法。</FONT>
<P>
<P>
<P>
<P>
<P>
<P><B><FONT size=4>Code</FONT></B><B><FONT size=4>:</FONT>


<P></B>
<P>
<P>
<P>
<P>
<P align=left>#include &lt;blitz/array.h&gt;


<P>
<P>
<P align=left>#include &lt;cstdlib&gt;


<P>
<P>
<P align=left>#include &lt;algorithm&gt;


<P>
<P>
<P align=left>#include &lt;vector&gt;


<P>
<P>
<P align=left>using namespace blitz;


<P>
<P>
<P align=left>
<P>
<P>
<P align=left>void Gauss_Jordan (Array&lt;double, 2&gt;&amp; A, Array&lt;double, 2&gt;&amp; b)


<P>
<P>
<P align=left>{


<P>
<P>
<P align=left>     int n = A.rows(), m = b.cols();


<P>
<P>
<P align=left>     int irow, icol;


<P>
<P>
<P align=left>     vector&lt;int&gt; indexcol(n), indexrow(n), piv(n);


<P>
<P>
<P align=left>
<P>
<P>
<P align=left>     for (int j=0; j&lt;n; ++j)


<P>
<P>
<P align=left>         piv.at(j) = 0;


<P>
<P>
<P align=left>     


<P>
<P>
<P align=left>     //寻找绝对值最大的元素作为主元


<P>
<P>
<P align=left>     for (int i=0; i&lt;n; ++i) {


<P>
<P>
<P align=left>         double big = 0.0;


<P>
<P>
<P align=left>
<P>
<P>
<P align=left>         for (int j=0; j&lt;n; ++j)


<P>
<P>
<P align=left>              if (piv.at(j) != 1)


<P>
<P>
<P align=left>                   for (int k=0; k&lt;n; ++k) {


<P>
<P>
<P align=left>                       if (piv.at(k) == 0) {


<P>
<P>
<P align=left>                            if (abs(A(j, k)) &gt;= big) {


<P>
<P>
<P align=left>                                 big = abs(A(j, k));


<P>
<P>
<P align=left>                                 irow = j;


<P>
<P>
<P align=left>                                 icol = k;


<P>
<P>
<P align=left>                                 if (irow == icol) break;


<P>
<P>
<P align=left>                            }


<P>
<P>
<P align=left>                       }


<P>
<P>
<P align=left>                   }


<P>
<P>
<P align=left>
<P>
<P>
<P align=left>         ++piv.at(icol);


<P>
<P>
<P align=left>         


<P>
<P>
<P align=left>         //进行行交换,把主元放在对角线位置上,列进行假交换,


<P>
<P>
<P align=left>         //使用向量indexrow和indexcol记录主元位置,     


<P>
<P>
<P align=left>         //这样就可以得到最终次序是正确的解向量。


<P>
<P>
<P align=left>         if (irow != icol) {


<P>
<P>
<P align=left>              for (int l=0; l&lt;n; ++l)


<P>
<P>
<P align=left>                   swap(A(irow, l), A(icol, l));


<P>
<P>
<P align=left>
<P>
<P>
<P align=left>              for (int l=0; l&lt;m; ++l)


<P>
<P>
<P align=left>                   swap(b(irow, l), b(icol, l));


<P>
<P>
<P align=left>         }


<P>
<P>
<P align=left>
<P>
<P>
<P align=left>         indexrow.at(i) = irow;


<P>
<P>
<P align=left>         indexcol.at(i) = icol;


<P>
<P>
<P align=left>         


<P>
<P>
<P align=left>         try {


<P>
<P>
<P align=left>              double pivinv = 1.0 / A(icol, icol);


<P>
<P>
<P align=left>
<P>
<P>
<P align=left>              for (int l=0; l&lt;n; ++l)


<P>
<P>
<P align=left>                   A(icol, l) *= pivinv;


<P>
<P>
<P align=left>              for (int l=0; l&lt;m; ++l)


<P>
<P>
<P align=left>                   b(icol, l) *= pivinv;


<P>
<P>
<P align=left>
<P>
<P>
<P align=left>              //进行行约化


<P>
<P>
<P align=left>              for (int ll=0; ll&lt;n; ++ll)


<P>
<P>
<P align=left>                   if (ll != icol) {


<P>
<P>
<P align=left>                       double dum = A(ll, icol);


<P>
<P>
<P align=left>
<P>
<P>
<P align=left>                       for (int l=0; l&lt;n; ++l)


<P>
<P>
<P align=left>                            A(ll, l) -= A(icol, l)*dum;


<P>
<P>
<P align=left>                       for (int l=0; l&lt;m; ++l)


<P>
<P>
<P align=left>                            b(ll, l) -= b(icol, l)*dum;


<P>
<P>
<P align=left>                   }


<P>
<P>
<P align=left>         }


<P>
<P>
<P align=left>         catch (...) {


<P>
<P>
<P align=left>              cerr &lt;&lt; "Singular Matrix";


<P>
<P>
<P align=left>         }


<P>
<P>
<P align=left>     }


<P>
<P>
<P align=left>}


<P>
<P>
<P align=left>
<P>
<P>
<P align=left>int main()


<P>
<P>
<P align=left>{


<P>
<P>
<P align=left>     //测试矩阵


<P>
<P>
<P align=left>     Array&lt;double, 2&gt; A(3,3), b(3,1);


<P>
<P>
<P align=left>     A =  10,-19,-2,


<P>
<P>
<P align=left>         -20, 40, 1,


<P>
<P>
<P align=left>           1,  4, 5;


<P>
<P>
<P align=left>
<P>
<P>
<P align=left>     b = 3,


<P>
<P>
<P align=left>         4,


<P>
<P>
<P align=left>         5;


<P>
<P>
<P align=left>     


<P>
<P>
<P align=left>     Gauss_Jordan(A, b);


<P>
<P>
<P align=left>     


<P>
<P>
<P align=left>     cout &lt;&lt; "Solution = " &lt;&lt; b &lt;&lt;endl;


<P>
<P>
<P>}


<P>
<P>
<P>
<P>
<P>
<P><B><FONT size=4>Result</FONT></B><B><FONT size=4>:</FONT>


<P></B>
<P>
<P><B>
<P></B>
<P>
<P>Solution = 3 x 1


<P>
<P>
<P>[   4.41637


<P>
<P>
<P>    2.35231


<P>
<P>
<P>   -1.76512 ]


<P>
<P>
<P>
<P>
<P>
<P>
<P>
<P>
<P><FONT size=4>     从代码的过程可以看出,矩阵A的逆在A中逐步构造,最终矩阵A演变成单位矩阵,解向量X也逐步替代右端项向量,且使用同一存储空间。</FONT>
<P>
<P>
<P>
<P>
<P>
<P>
<P>
<P>
<P><FONT size=3>注释:主元,又叫主元素,指用作除数的元素</FONT>
<P>

</P>
[此贴子已经被作者于2004-6-3 22:15:49编辑过]

ilikenba 发表于 2004-6-3 22:28

<P>消元法相当于在一个多面体的上,遍历各个边去寻找,所以很慢的!</P>

lckboy 发表于 2004-6-3 22:32

嗯,就是慢,不过精度还算可以,用了blitz++库,发挥C++到极点了,现在应该比Fortran编写的要快的

ilikenba 发表于 2004-6-3 22:51

不会吧,Frotran和C++的速度一样,很难分出上下的!

lckboy 发表于 2004-6-3 23:01

如果C++不用模板,Frotran是比C++快的,尤其在数值算法上,但Blitz++库就针对科学技术开发的,非常的快~~上千条方程的方程组很快就可以算好,当然还要使用编译器的优化

ilikenba 发表于 2004-6-29 10:34

Intel出了Fortran 8了,据说性能又提高了20%!

loooog12 发表于 2010-7-27 13:28

数值计算强烈支持Fortran

后青春期的诗 发表于 2012-2-5 14:23

数值计算强烈支持Fortran

zqyzixin 发表于 2012-8-1 02:18

我继续顶你!太好的帖子了 支持

MichaeLonger 发表于 2014-6-30 18:17

路过。。。
页: [1] 2
查看完整版本: [原创]全主元Gauss-Jordan消元法(Blitz++库)