みけCATのにっき(仮)
つれづれなるまゝに、日くらし、PCにむかひて、心に移りゆくよしなし事を、そこはかとなく書きつくれば、あやしうこそものぐるほしけれ。
(本当か!?)
出典

ガウスの消去法

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

ガウスの消去法

投稿記事 by みけCAT » 13年前

前の日記で、クラーメルの公式を利用してn元連立方程式を解いてみました。
しかし、n=9程度で使い物にならなくなってしまいました。
そこで、やっぱり基本のガウスの消去法を実装してみました。
ガウスの消去法 - Wikipedia
作ったコードがこちら。

CODE:

#include 
#include 

#if 0
#define DO_TEST_PRINT
#endif

double** allocMatrix(int n) {
	double** result;
	int i;
	/*列のメモリを確保*/
	result=malloc(sizeof(double*)*n);
	/*メモリ確保エラー*/
	if(result==NULL)return NULL;
	/*各行のメモリを確保*/
	for(i=0;i=0;i--)free(result[i]);
			free(result);
			return NULL;
		}
	}
	return result;
}

void freeMatrix(double** mat,int n) {
	int i;
	for(i=0;i=n) {
				/*エラー*/
				freeMatrix(mat2,n);
				freeVector(vec2);
				return 0;
			}
			/*交換*/
			tempp=mat2[i];
			mat2[i]=mat2[j];
			mat2[j]=tempp;
			tempd=vec2[i];
			vec2[i]=vec2[j];
			vec2[j]=tempd;
		}
		/*係数を1にする*/
		for(j=i+1;j=0;i--) {
		for(j=i-1;j>=0;j--) {
			vec2[j]-=mat2[j][i]*vec2[i];
			mat2[j][i]=0;
		}
	}
#ifdef DO_TEST_PRINT
	/*テスト出力*/
	puts("後退代入");
	for(i=0;i<n;i++) {
		for(j=0;j<n;j++) {
			fprintf(stderr,"%7.1f",mat2[i][j]);
		}
		fprintf(stderr,"%7.1f\n",vec2[i]);
	}
#endif
	/*結果を代入*/
	for(i=0;i<n;i++)result[i]=vec2[i];
	/*コピーした方程式を開放*/
	freeMatrix(mat2,n);
	freeVector(vec2);
	/*成功*/
	return 1;
}

/*
使い方
まず、n元連立方程式を解く場合のnを整数で入力します。
次に、例えばn=3のとき、
一つの式がax+by+cz=dだとしたら、
a b c d
と入力します。
これをn回繰り返します。
すると、結果が最初の変数から順に表示されます。
この例だと
x
y
z
と表示されます。
入力のa、b、c、dと出力のx、y、zには具体的な実数が入ります。 
*/

int main(void) {
	int n;
	double** mat;
	double* vec;
	double* result;
	int i,j;
	/*nの入力*/
	scanf("%d",&n);
	if(n<=0)return 1;
	/*行列の確保*/
	mat=allocMatrix(n);
	if(mat==NULL)return 1;
	/*ベクトルの確保*/
	vec=allocVector(n);
	if(vec==NULL) {
		freeMatrix(mat,n);
		return 1;
	}
	result=allocVector(n);
	if(result==NULL) {
		freeMatrix(mat,n);
		freeVector(vec);
		return 1;
	}
	/*値の入力*/
	for(i=0;i<n;i++) {
		for(j=0;j<n;j++) {
			scanf("%lf",&mat[i][j]);
		}
		scanf("%lf",&vec[i]);
	}
	/*計算*/
	if(solveHouteisiki(result,mat,vec,n)) {
		/*結果の表示*/
		for(i=0;i<n;i++) {
			printf("%g\n",result[i]);
		}
	} else {
		puts("error");
	}
	/*メモリの開放*/
	freeMatrix(mat,n);
	freeVector(vec);
	freeVector(result);
	/*正常終了*/
	return 0;
}
前の日記の連立方程式を作るプログラムとパイプでつなげてみたところ、
20元連立方程式の正しい解を一瞬で出してくれました。
うん、やっぱ普通のアルゴリズムはすばらしい。
オフトピック
何がゼロ除算が怖いだよ。俺のバカ。

アバター
GRAM
記事: 164
登録日時: 14年前

RE: ガウスの消去法

投稿記事 by GRAM » 13年前

Gauss-Jordan法も使いますが、より大規模な実用計算ではLU分解法というのがよく使われたりします。
理論的な計算量はおんなじですが、0要素が多いときに計算を大幅に省けたり、同じ行列を使う時
逆行列を求めるのと同じ計算量で解が出せるため重宝されます。プログラミングはより簡単になるので興味があれば調べてみてはどうでしょう?