[原创]全主元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 <blitz/array.h>
<P>
<P>
<P align=left>#include <cstdlib>
<P>
<P>
<P align=left>#include <algorithm>
<P>
<P>
<P align=left>#include <vector>
<P>
<P>
<P align=left>using namespace blitz;
<P>
<P>
<P align=left>
<P>
<P>
<P align=left>void Gauss_Jordan (Array<double, 2>& A, Array<double, 2>& 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<int> indexcol(n), indexrow(n), piv(n);
<P>
<P>
<P align=left>
<P>
<P>
<P align=left> for (int j=0; j<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<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<n; ++j)
<P>
<P>
<P align=left> if (piv.at(j) != 1)
<P>
<P>
<P align=left> for (int k=0; k<n; ++k) {
<P>
<P>
<P align=left> if (piv.at(k) == 0) {
<P>
<P>
<P align=left> if (abs(A(j, k)) >= 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<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<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<n; ++l)
<P>
<P>
<P align=left> A(icol, l) *= pivinv;
<P>
<P>
<P align=left> for (int l=0; l<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<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<n; ++l)
<P>
<P>
<P align=left> A(ll, l) -= A(icol, l)*dum;
<P>
<P>
<P align=left> for (int l=0; l<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 << "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<double, 2> 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 << "Solution = " << b <<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编辑过] <P>消元法相当于在一个多面体的上,遍历各个边去寻找,所以很慢的!</P> 嗯,就是慢,不过精度还算可以,用了blitz++库,发挥C++到极点了,现在应该比Fortran编写的要快的 不会吧,Frotran和C++的速度一样,很难分出上下的! 如果C++不用模板,Frotran是比C++快的,尤其在数值算法上,但Blitz++库就针对科学技术开发的,非常的快~~上千条方程的方程组很快就可以算好,当然还要使用编译器的优化 Intel出了Fortran 8了,据说性能又提高了20%! 数值计算强烈支持Fortran 数值计算强烈支持Fortran 我继续顶你!太好的帖子了 支持 路过。。。
页:
[1]
2