關於 Gauss Jordan (不知道是不是這麼拼) 消去法
基本上大家都知道怎麼做,
這裡的 code 分二段,一段是用高斯消去法求反矩陣(MINVERSE),
另一段是用高期消去法求連立方程式之解
以下的 code 便是實現其作法
若對 code 有問題,歡迎回覆進行討論
// =======================================
// author : edison.shih.
// filename: matrix.cpp
// date : 2010/2/7
// mail : forget72@hotmail.com
// ** all copyright reverve **
// =======================================
// ==============================
// 計算反矩陣
/*
use gauss jodarn method.
return value:
-1: have a row all 0
0 : exist inverse
1 : have a col all 0
*/
int MINVERSE( double **a,
unsigned dim,
double **_result)
{
unsigned i, j;
double x=0.0;
SetUnitMatrix(_result, dim);
double **tmp = (double**)malloc(sizeof(double*)*dim);
for(i=0; i<dim; i++) tmp[i] = (double*)malloc(sizeof(double)*dim);
CopyMatrix(tmp, a, dim, dim);
for(i=0; i<dim; i++){
// 該列全為0, return -1
if(IsRi0(tmp, i, dim)) return -1;
if(tmp[i][i]==0.0){
// 交換至該元素為非0
bool flag = false;
for(j=i+1; j<dim; j++){
Rij(tmp, i, j, dim);
Rij(_result, i, j, dim);
if(tmp[i][i]!=0.0) {
break;
flag = true;
}
}
// 交換不到非0 元素,return 1
if(flag==false) return 1;
}
// 以下精華
x = 1.0 / tmp[i][i];
Rix(tmp, i, x, dim);
Rix(_result, i, x, dim);
for(j=0; j<dim; j++){
if(i==j) continue;
x = -tmp[j][i] / tmp[i][i];
Rijx(tmp, i, j, x, dim);
Rijx(_result, i, j, x, dim);
}
}
for(i=0; i<dim; i++) free(tmp[i]);
free(tmp);
return 0;
}
// ==============================
// 使用 gauss jordan 求連立方程式
/*
return value:
-1: 無解
0 : 有一解
1 : 無限多解
*/
int GAUSSJORDAN(double **a,
double *ans,
unsigned dim)
{
unsigned i, j;
double x=0.0;
double **tmp = (double**)malloc(sizeof(double*)*dim);
for(i=0; i<dim; i++) tmp[i] = (double*)malloc(sizeof(double)*(dim+1));
CopyMatrix(tmp, a, dim, dim+1);
for(i=0; i<dim; i++){
// 該列全為0, 無限多解, return 1
if(IsRi0(tmp, i, dim+1)) return -1;
if(tmp[i][i]==0.0){
// 交換至該元素為非0
bool flag = false;
for(j=i+1; j<dim; j++){
Rij(tmp, i, j, dim+1);
if(tmp[i][i]!=0.0) {
break;
flag = true;
}
}
// 交換不到非0 元素,無解, return -1
if(flag==false) return -1;
}
// 以下精華
x = 1.0 / tmp[i][i];
Rix(tmp, i, x, dim+1);
for(j=0; j<dim; j++){
if(i==j) continue;
x = -tmp[j][i] / tmp[i][i];
Rijx(tmp, i, j, x, dim+1);
}
}
for(i=0; i<dim; i++) {
ans[i] = tmp[i][dim];
}
for(i=0; i<dim; i++) free(tmp[i]);
free(tmp);
return 0;
}

原來大家都這麼客氣.. 不過很開心我寫的東西總算有人看了 (淚) 現在回覆之前有人 mail 給我的問題: 這份 source code 裡面有些 function 你似乎是找不到在哪出現, 那是當然滴!! 因為直接用 google 到這篇的話, 應該是沒辦法連上幾篇都一起看吧!! so.. 你可以按一下 "數值分析" 這一類, 只要跟 matrix 有關的, 函數就可能會在裡面.. 特別強調, 我覺得 Matrix 有幾個基本 operation 常用到 所以才寫了頭二篇當基本函式庫 連結如下… [C語言數值分析] 行列式(矩陣)基本運算-1 http://edisonshih.pixnet.net/blog/post/30287135 [C語言數值分析] 行列式(矩陣)基本運算-2(行列式 加減乘 - 轉置) http://edisonshih.pixnet.net/blog/post/30287144
傳說中的 Gaussian Elimination啊 可以解「無限元」「一次」方程式耶 老師曾經問過我們有沒有打算把他Coding出來 XD
呵..這是最陽春版的.. 不過可以解大多數你說的問題
不過這裡好像還沒考慮determinant = 0的情況 加上後面文章的行列式code就完美了~
有唷.. determinant = 0 事實上我的 code 隱約中是有判斷的,在過程中我不斷的去判斷 1. 該列有沒有元素全為0的; 2. 該軸是不是換不到為非0的元素。這二個事實上就是在判斷 det 是否為0。 (所以才有三種傳回值..)
但有些矩陣的元素沒有0 它的determinant也是0不是嗎?如: 2 4 3 6
不知您上面是專指 "行列式" 還是 "反矩陣", any way, 我都說明一下, /* -1: have a row all 0,0 : exist inverse,1 : have a col all 0 */ 程式裡面算的流程是這樣的.. |2 4|-----> | 1 2 |---->| 1 2 | |3 6|-----> | 3 6 |---->| 0 0 | ---> 進入第二列時該列全為0, return -1, 程式碼是這行: if(IsRi0(tmp, i, dim)) return -1; 如你所說, 事實上沒有元素是0, 但在簡化算反矩陣過程中, 事實上就會發生 det=0 的情形。故您說的那種情形, 是可以經由列運算得到的結果的。另交換不到非零元素傳回 1 指的是化簡過程中發生這種情形.. | 1 0 5 0| --> row1 完成 | 0 1 2 0| --> row2 完成 | 0 0 0 1| --> 輪到 row3 | 0 0 0 0| 現在 row3 的樞點 (3,3) 往下找不到0,雖該列未全部為0,if(IsRi0(tmp, i, dim)) 不成立,但由於向下幾列換不到樞點,於是就傳回另一失敗值。這裡我失敗值有二個, +1, -1, 唯一成功值只會傳0,解釋下來後,不知您是否認為這程式還算合理?
喔喔原來如此 那我再研究一下我哪裡寫錯了0.0
請問該怎麼做輸入陣列的部分?? 我想輸入↓ 1,-2,3,9 -1,3,0,-4 2,-5,5,17 我現在執行您的"使用G-J 求連立方程式"的程式就會卡在cmd畫面,按鍵盤也不會出現東西,請問該怎麼辦??
這裡的程式碼是較單純的,假設已先將數值正確輸入至陣列裡去。 若您的問題是如果將目前的輸入格式,正確的轉到陣列裡去,再做處理,我想應是字串處理那裡不熟。解決方案很多,C 語言 strchr , strtok, 甚至手動去處理都行 ; C++ stringstream 等,這些你可查一下其用法,我就不再詳述了。