ガウスの消去法のプログラムで上手くいかない

このQ&Aのポイント
  • ガウスの消去法(部分ピボット選択)のプログラムを組んでみたつもりなのですが、上手くいきません。
  • 間違いだらけだと思いますが、アドバイスをして頂けませんでしょうか?
  • #ガウスの消去法 #プログラム #アドバイス
回答を見る
  • ベストアンサー

ガウスの消去法のプログラム

ガウスの消去法(部分ピボット選択)のプログラムを組んでみたつもりなのですが上手くいきません。 間違いだらけだと思いますがどうかアドバイスをして頂けませんでしょうか? #include <stdio.h> double main(void){ int i,j,k,N,M,m; double A[N+1][N+1][N+1],B[j],S,X[N+1]; printf("次数の入力。\n"); scanf("%d",&N); for(k=1;k<=N;k++){ for(i=1;i<=N;i++){ for(j=1;j<=N+1;j++){ A[k][i][j]=0; } } } for(i=1;i<=N;i++){ for(j=1;j<=N+1;j++){ printf("係数の入力.\n A[1][%d][%d]?\n",i,j); scanf("%f",&A[1][i][j]); } } for(k=2;k<=N;k++){ if(A[k-1][k-1][k-1]=0){ for(M=k;M<=N;M++){ if(A[k-1][M][k-1]!=0){ for(j=k-1;j<=N+1;j++){ B[j]=A[k-1][k-1][j]; A[k-1][k-1][j]=A[k-1][M][j]; A[k-1][M][j]=B[j]; } goto abc; } else {printf("解は無い\n");} } } abc: for(i=k;i<=N;i++){ for(j=k;j<=N+1;j++){ A[k][i][j]=A[k-1][i][j]-(A[k-1][i][k-1]/A[k-1][k-1][k-1])*A[k-1][k-1][j]; } } X[N]=A[N][N][N+1]/A[N][N][N]; printf("解X(N)は %f 。\n",X[N]); for(k=N-1;k>=1;k--){ S=0; for(m=N;m>=k+1;m--){ S+=A[k][k][m]*X[m]; } X[k]=(A[k][k][N+1]-S)/A[k][k][k]; printf("解X(%d)は %f 。\n",k,X[k]);} } }

noname#6073
noname#6073

質問者が選んだベストアンサー

  • ベストアンサー
  • kary
  • ベストアンサー率55% (10/18)
回答No.1

ガウス消去法には3元配列は必要なく(Cで3元配列は使えないと思うのですが)2元配列でできます。概要は、例えば3元の連立方程式を解く場合、配列はX[3][4]を確保し、未知数の係数3×3を0~2列に、既知数の定数を3列に代入します。ピボット選択法ということですが、説明を簡単にするために、最大値の選択をしないとすると、 1. 0行目の全要素X[0][0~3]をX[0][0]で割る。 2. 1行目に対してX[1][i]-=X[0][i]*X[1][0](i=0~3)を行う。2行目も同様にする。これにより、0列目はX[0][0]=1.0、X[1~2][0]=0.0となる。 これを1ステップとして、次のステップは、 1. 1行目の全要素X[1][1~2]をX[1][1]で割る。(X[1][0]は0.0なので割らなくても良い) ... これを2行目まで繰り返すと、X[0~2][0~2]は対角要素のみが1.0で、その他は0.0の行列となり、X[0~2][3]が答えとなる。 このようにすると、X[3][4]の配列のみで計算ができます(ループカウンタ等は必要ですが)。ピボット選択法の場合は、1.の前に行の入れ替えをします。 ガウス消去法についての知識がおありな様でしたので、とりあえず概要のみの回答とさせて頂きました。(こんなことぐらい知ってるよ、という内容で参考にならないかも知れませんが...)

noname#6073
質問者

お礼

こんなに早く回答してくださって有難うございました。 >こんなことぐらい知ってるよ、という内容で参考にならな>いかも知れませんが・・・ 知らない事ばかりです、とても参考になりました。 C言語に関する知識なんかは本当に皆無に近い状態でしたのでご指摘を受けなければ、解らないままになっていたと思います

関連するQ&A

  • ガウスのの単純消去法のプログラムです。

    ガウスのの単純消去法のプログラムです。 前進消去の第k段階が終わった段階でaij,biが表示されるようにしたいんですがどうすればいいでしょうか↓ よろしくお願いします。 #include<stdio.h> #include<stdlib.h> #include<math.h> #define ERROR -1 #define EPS 1.0e-15 int gausssimp(double *, double *, double *, int); int main(void) { double *a,*b,*x,val; char s[32]; int i,j,n,result; printf("Input size n="); gets(s); sscanf(s,"%d",&n); if((a=(double *)calloc(n*n,sizeof(double)) ) == NULL){ fprintf(stderr,"Memory allocation error\n"); exit(-1); } if((b=(double *)calloc(n,sizeof(double))) == NULL){ fprintf(stderr,"Memory allocation error\n"); exit(-1); } if((x=(double *)calloc(n,sizeof(double))) == NULL){ fprintf(stderr,"Memory allocation error\n"); exit(-1); } /* A,b の成分を入力 */ printf("----- A -----\n"); for(i=0; i<n; i++){ for(j=0; j<n; j++){ printf("a(%2d,%2d)=",i+1,j+1); gets(s); sscanf(s,"%lf",&val); a[n*i+j]=val; } } printf("\n----- b -----\n"); for(i=0; i<n; i++){ printf("b(%2d)=",i+1); gets(s); sscanf(s,"%lf",&val); b[i]=val; } /* Gaussの単純消去法による求解 */ result = gausssimp(x,a,b,n); /* 解の表示 */ if(result == ERROR){ printf("ERROR occurs. pivot 0\n"); } else { printf("\n----- solution -----\n"); for(i=0; i<n; i++){ printf("x(%2d)=%.8e\n",i+1, x[i]); } } free(a); free(b); free(x); return 0; } int gausssimp(double *x, double *a, double *b, int n) { int i,j,k; double tmp,p,sum; /* step 1: 前進消去 */ /**** 追加 ****/ /* 前進消去の各段階を終えるごとに,式がどのように変化しているかわかるように表示する */ /**************/ for(k=0; k<n-1;k++){ if(a[n*k+k] == 0.0) { /* ピボットの値が0.割り算でエラーが起きる.*/ return ERROR; } else { /* k+1番目以降の式から x[k] の項を消去 */ for(i=k+1; i<n; i++){ p=a[n*i+k]/a[n*k+k]; for(j=0; j<n; j++){ a[n*i+j]=a[n*i+j]-p*a[n*k+j]; } b[i]=b[i]-p*b[k]; printf("a[%d %d]=%d b[%d]=%d",i,j,a[n*i+j]-p*a[n*k+j],i,b[i]-p*a[n*k+j]); ↑これではできませんでした。。。 } /**********************************/ } printf("k=%d\n",k); } /* step 2: 後退代入 */ for(k=n-1; k>=0; k--){ if(fabs(a[n*k+k]) < EPS) return(ERROR); sum=0.0; for(j=k+1; j<n; j++) sum+=a[n*k+j]*x[j]; x[k]=(b[k] - sum)/a[k*n+k]; } return 0; }

  • ガウスの消去法のプログラムについて

    ガウスの消去法のプログラムについて #include <stdio.h> #define N 3 void main(void) { static double a[N][N+1]={{3.0, 1.0, 1.0, 8.0}, {6.0, 2.0, 3.0, 4.0}, {9.0, 4.0, 5.0, 12.0}}; double d; int i,j,k; for (k=0;k<N-1;k++){ for (i=k+1;i<N;i++){ d=a[i][k]/a[k][k]; for (j=k+1;j<=N;j++) a[i][j]=a[i][j]-a[k][j]*d; } } for (i=N-1;i>=0;i++){ d=a[i][N]; for (j=i+1;j<N;j++){ d=d-a[i][j]*a[j][N]; a[i][N]=d/a[i][i]; } } for (k=0;k<N;k++){ printf("x%d=%f\n",k+1,a[k][N]); } } というプログラムを実行したら 8-5.c: In function `main': 8-5.c:4: warning: return type of `main' is not `int' と出たのですがどこを直せばよいのでしょうか?><

  • ガウスの消去法、後退代入について

    ガウスの消去法で、n変数n式の連立一次方程式を解くプログラムを 作っています。 ですが、前進消去およびピボット選択ははおそらくできたのですが 後退代入が悪いのか、答えが出ません。 もしかしたら前進消去部分も悪いのかもしれませんが;; いろいろ調べたのですが どうしたら直るのかわからなくなってしまいました。 どのようにして直せばいいのか教えてください。 プログラムは以下です。 #include<stdio.h> #include<math.h> #define SIZE 100/*上限MAXのマクロ定義*/ #define EPS (1.0e-5) int main() { /*変数宣言*/ int n; /*連立方程式の式数*/ int i; /*1つ目のループカウンタ*/ int j; /*2つ目のループカウンタ*/ int k;/*3つ目のループカウンタ*/ int pivot; /*pivot選択を行う際に使用する変数*/ double max; /*pivot選択用の絶対値が最大の値*/ double matrix_a[SIZE][SIZE]; /*変数xijの係数aij*/ double matrix_b[SIZE]; /*式iの定数項bi*/ double a_hozon;/*matrix_aの値を一時保存する変数*/ double b_hozon;/*matrix_bの値を一時保存する変数*/ double r_hozon;/*前進消去法をする時使用する値を一時保存する変数*/ int l; int m; /*入力処理*/ /*未知数nの入力*/ printf("n変数n式の連立一次方程式を解きます。\n"); printf("式数n(1~100)を入力してください。 n=?\n"); scanf("%d",&n); /*未知数nのチェック*/ if(n>SIZE||n<1) { printf("\n\nn=%dはプログラムの利用可能範囲外です。\n",n); return -1; } printf("%d変数%d式の一次方程式を入力して下さい。\n",n,n); printf("入力は、式毎に係数、定数項の順に行ってください。\n\n"); printf("連立一次方程式の拡大係数行列を表示します。\n"); for(i=0; i<n; i++) { for(j=0; j<n; j++) { scanf("%lf",&matrix_a[i][j]); } scanf("%lf",&matrix_b[i]); } for(i=0; i<n; i++) { for(j=0; j<n; j++) { printf("%6.2f",matrix_a[i][j]); } printf("|%6.2f\n",matrix_b[i]); } printf("計算します。\n"); /*pivot選択*/ for(k=0; k<n; k++) { max=0.0; pivot=0; for(i=k; i<n; i++) { if(fabs(matrix_a[i][k])>max) { max=fabs(matrix_a[i][k]); pivot=i; } } if(matrix_a[pivot][k]==0.0) { printf("正則性なし\n"); } if(pivot!=k) { for(j=0; j<n; j++) { a_hozon = matrix_a[k][j]; matrix_a[k][j] = matrix_a[pivot][j]; matrix_a[pivot][j] = a_hozon; } b_hozon = matrix_b[k]; matrix_b[k] = matrix_b[pivot]; matrix_b[pivot] = b_hozon; } } /*入れ換え後の行列を表示*/ for(l=0; l<n; l++) { for(m=0; m<n; m++) { printf("%6.2f",matrix_a[l][m]); } printf("|%6.2f\n",matrix_b[l]); } /*消去法*/ for(k=0; k<n; k++) { for(i=k+1; i<n-1; i++) { r_hozon = matrix_a[i][k]/matrix_a[k][k]; for(j=k; j<n; j++) { matrix_a[i][j] = matrix_a[i][j]-r_hozon*matrix_a[k][j]; } matrix_b[i] = matrix_b[i]-r_hozon*matrix_b[k]; } } /*後退代入*/ for(i=n-1; i>=0; i--) { matrix_b[i]=0.0; for(j=i+1; j<n; j++) { matrix_b[i]=matrix_b[i]-matrix_a[i][j]*matrix_b[j]; } } /* for(i=n-1; i>0; i--) { temp = 0.0; for(j=i+1; j<n; j++) { xn = b[n]/a[n][n]; xn-1 = (-a[n-1][n]*x[n]+b[n-1])/a[n-1][n-1]; xn-2 = (-a[n-2][n-1]*x[n-2]+a[n-2][n]*x[n]+b[n-2])/a[n-2][n-2]; xn-j = (-a[i][n-j]*x[i+1]+b[i])/a[i][i]; temp = matrix_a[][] temp=temp+matrix_a[i][j]*matrix_a[j][n]; matrix_a[i][n]=matrix_a[i][n]-temp; matrix_a[i][n]=matrix_a[i][n]/matrix_a[i][i]; } } */ /*不定、不能の判別*/ if(matrix_a[k][k]<EPS) { printf("解は一意に求まらない。\n"); return -1; } /*出力処理*/ printf("連立一次方程式の解を表示します。\n"); for(i=0; i<n; i++) { printf("x%d = %6.2f\n",i,matrix_b[i]); } return 0; }

  • Gaussの消去法のプログラムなんですがこれを利用して、消去法による行

    Gaussの消去法のプログラムなんですがこれを利用して、消去法による行列式の計算プログラムをつくりたいのですが難しくてよくわかりません。。。 教えていただきたいです。 困ってるのでよろしくお願いします。 int gauss(double *x, double *a, double *b, int n) { int i,j,k,m; double tmp,p,sum; for(k=0; k<n-1;k++){ printf("---- Step %d ----\n",k+1); printf("-- before --\n"); for( m = k;m < n;m++){ printf("%lf\n",a[n * m + k]); } printf("-- --\n"); j = pivot(a,n,k); if(j == ERROR) { return ERROR; } else { if(j != k) { for(i=0; i<n; i++){ tmp = a[n*k+i]; a[n*k+i] = a[n*j+i]; a[n*j+i] = tmp; } tmp=b[j]; b[j]=b[k]; b[k]=tmp; } } printf("-- after --\n"); for( m = k;m < n;m++){ printf("%lf \n",a[n * m + k]); } for(i=k+1; i<n; i++){ p=a[n*i+k]/a[n*k+k]; for(j=0; j<n; j++){ a[n*i+j]=a[n*i+j]-p*a[n*k+j]; printf("a[%d %d]=%lf",i,j,a[n*i+j]); } b[i]=b[i]-p*b[k]; printf("b[%d]=%lf\n",i,b[i]); } printf("k=%d\n",k); /*--------------------------------------------------------------------------*/ } /* step 2: 後退代入 */ for(k=n-1; k>=0; k--){ if(fabs(a[n*k+k]) < EPS){ return(ERROR); } sum=0.0; for(j=k+1; j<n; j++){ sum+=a[n*k+j]*x[j]; } x[k]=(b[k] - sum)/a[k*n+k]; } return 0; } int pivot(double *a, int n, int k) { int i,m; double d; /* ピボットの探索 */ m = k; d = fabs(a[k*n+k]); for(i=k+1; i<n; i++){ if(fabs(a[n*i+k]) > d){ m = i; d = fabs(a[n*i+k]); } } if(fabs(d) < EPS) { return ERROR; } else { return m; } }

  • ガウスの消去法のプログラムがどうしてもうまく動きません。

    こんにちは。あまりにも困ってしまったので質問させていただきました。 よろしければご回答をよろしくお願い致します。 さて、今ガウスの消去法のプログラムを作っているのですが、 どうしてもどうしても、正しい解を得ることができません。 今日はほぼ徹夜でずっとパソコン画面とにらめっこしていたのですが、 何をしてもどこをいじってもさっぱり上手く行かず、正直嫌気が差し始めているところです(泣) Cの詳しい知識などは皆無に近い人間ですが、 こんなド素人を助けていただけませんか? ↓が僕の書いたソースコードです。間違いだらけで非常に見苦しいと思いますがお許し下さい。 #include<stdio.h> #include<stdlib.h> #include<math.h> int main(){ float a[3][3] = { {-2, 4000000, -6000000}, {-2, 0.03, -0.2}, {1, -0.2, -0.05} }; float b[3] = {5000000, 0.1, 0.1}; float max[3]; float maxp; float temp; float x[3]; float m; int pivot = 0; int i,j,k; for( k = 0; k < 3; k++ ){ /* scaling */ for( j = 0; j < 3; j++ ){ max[j] = 0; for( i = 0; i < 3; i++ ){ if( max[j] < fabs(a[j][i]) ) max[j] = fabs(a[j][i]); } } for( j = 0; j < 3; j++ ){ for( i = 0; i < 3; i++ ){ a[j][i] = a[j][i] / max[j]; } b[j] = b[j]/max[j]; } /* pivoting */ for( j = k; j < 3; j++ ){ if ( maxp < fabs(a[j][k]) ){ pivot = j; maxp = fabs(a[j][k]); } } for( i = k; i < 3; i++ ){ temp = a[k][i]; a[k][i] = a[pivot][i]; a[pivot][i] = temp; } temp = b[k]; b[k] = b[pivot]; b[pivot] = temp; /* forword elimination */ for( j = k+1; j < 3; j++ ){ m = a[j][k] / a[k][k]; for( i = k; i < 3; i++ ){ a[j][i] -= a[k][i] * m; } b[j] -= b[k] * m; } /* backward substitution */ for( j = 1; j >= 0; j-- ){ for( i = j+1; i > 3; i++){ m += a[j][i] * b[i]; x[j] -= m; x[j] = x[j] / a[j][j]; } } } for( j = 0; j < 3; j++ ){ for( i = 0; i < 3; i++ ){ printf("%f ", a[j][i]); } printf("\n"); printf("%f", x[j]); } return(0); } ご回答お待ちしております。 改めて、お見苦しいソースコードだったとは思いますが、ご容赦下さい。

  • c言語 行列のn階乗のプログラム

      1 2 -1 D= 3 0 -2   -1 1 2 の3次正方行列のn乗を計算するプログラムを作成しています。 いろいろと試してみましたがうまくいきません。 どなたか教えていただけるとうれしいです。 よろしくおねがいします。 #include <stdio.h> int main(void) { int a[3][3]={ {-1,2,-1},{3,0,-2},{-1,1,2} }; int b[3][3]={ {-1,2,-1},{3,0,-2},{-1,1,2} }; int s[3][3]; int m,n; int i,j,k; printf("[A]^n;n = ");scanf("%d",&n); for (m=2;m <= n;m++){ for (i=0;i<3;i++){ for (j=0;j<3;j++){ s[i][j] = 0; for(k=0;k<3;k++){ s[i][j] =s[i][j] + a[i][k] * b[k][j]; } } } for(i=0;i<3;i++){ for(j=0;j<3;j++){ b[i][j]=s[i][j]; } } printf("%3d",s[i][j]); putchar('\n'); } return (0); }

  • c言語のプログラムで行列の積を計算する

    指定された行・列数(それぞれ10以下とする)の行列 X, Y の積 Z = X × Y を求めるプログラムを作成せよ.行列の要素はすべて整数とする. このプログラムで行と列の成分を入力するときに、1列になってしまうのですがどうしたらちゃんと入力できますか? int main(void) { double A[10][10]; double B[10][10]; int i,j,m,n,p,k; printf("行列xの行数は?:"); scanf("%d",&m); printf("行列xの列数(行列yの行数)は?:"); scanf("%d",&n); printf("行列yの列数は?:"); scanf("%d",&p); printf("行列xを入力してください。\n"); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { scanf("%d", &A[i][j]); } } printf("行列yを入力してください。\n"); for (i = 0; i < n; i++) { for (j = 0; j < p; j++) { scanf("%d", &B[i][j]); } }

  • C言語 プログラミング 行列演算

    下記のプログラムのおかしい点と解決法を教えてください。 コンパイルは通りますがうまく動きません。。 #include<stdio.h> #define MAX 500 int main(void){ int matrA[MAX][MAX],matrB[MAX][MAX],matrC[MAX][MAX],l,m,n,i,j,k; printf("lとmを入力してください:"); scanf("%d",&l); scanf("%d",&m); printf("行列Aを入力してください"); for(i=0;i<l;i++){ printf(">"); for(j=0;l<m;j++){ scanf("%d",&matrA[i][j]); } printf("\n"); } printf("nを入力してください(m = %d):",m); scanf("%d",&n); printf("行列Bを入力してください"); for(i=0;i<m;i++){ printf(">"); for(j=0;j<n;j++){ scanf("%d",&matrB[i][j]); } printf("\n"); } printf("C=\n"); for(i=0;i<l;i++){ for(j=0;j<n;j++){ for(k=0;k<m;k++){ matrC[i][j]+=matrA[i][k]*matrB[k][j]; } printf("%d",matrC[i][j]); } printf("\n"); } }

  • C言語のプログラムで質問です。

    C言語のプログラムで質問です。 これは、2元1次連立方程式の解を求めるプログラムです。 このプログラムを (1)3元1次連立方程式の解を求めるプログラムにする (2)係数行列、定数行列(6、7行目)をキーボードからの入力にする。 ようにしたいのですが、どうすればよいでしょうか。 前半の部分を変えれば良いようなのですが分かりません。教えてください。 #include <stdio.h> #include <math.h> /* gauss22.c */ #define N 2 main(){ double A[N][N]={1.,4.,3.,2.}, Aa[N][N]; /*簡単のため係数行列を予め指定*/ double b[N]={4.,5.}, x[N], bb[N], e[N]; /*簡単のため定数ベクトルを予め指定*/ int n=2; int i, j, k; double akk, aik, s; /* save original coefficients */ for (i=0; i<n; i++){ for (j=0; j<n; j++){ Aa[i][j]=A[i][j]; } bb[i]=b[i]; } /* forward operation */ for (k=0; k<n-1; k++){ akk=1/A[k][k]; for (i=k+1; i<n; i++){ aik=-A[i][k]*akk; for (j=k+1; j<n; j++){ A[i][j]+=aik*A[k][j]; } b[i]+=aik*b[k]; } for (j=k+1; j<n; j++){ A[k][j]*=akk; } b[k]*=akk; } /* backward operation */ x[n-1]=b[n-1]/A[n-1][n-1]; for (k=n-2; k>=0; k--){ s=0.0; for (j=k+1; j<n; j++){ s+=A[k][j]*x[j]; } x[k]=b[k]-s; } /* chek */ for (i=0; i<n; i++){ s=0.0; for (j=0; j<n; j++){ s+=Aa[i][j]*x[j];} e[i]=s-bb[i]; printf("x(%d)=%f error=%f?n",i, x[i], e[i]); } }

  • 以前も同じ質問したのですがもう一度お願いします

    以前も同じ質問したのですがもう一度お願いします プログラミングで3行3列の行列Aに対しAの2乗、Aの3乗を求めるプログラムを作成したいのですが下記のプログラムでは3行3列まで表示できません どこが間違えているのか修正していただけないでしょうか? #include <stdio.h> int main(){ int z[3][3]; int w[3][3]; int x[3][3]={1,2,3,4,5,6,7,8,9}; int n,m; int i,j,k; printf("z[3][3] : \n"); for(i=0;i<3;i++) { for(j=0;j<3;j++) {printf("z[%d][%d] = ",i,j); scanf ("%d",&z[i][j]); } } printf("m for [z]^m ="); scanf ("%d",&m); for(n=0;n<m;n++) { for(i=0;i<3;i++) { for(j=0;j<3;j++) { w[i][j] = 0; for(k=0;k<3;k++) { w[i][j] += x[i][k]*z[k][j]; } } } for(i=0;i<3;i++) { for(j=0;j<3;j++) { x[i][j] = w[i][j]; } } printf("[z]^%d\n",n+1); for(i=0;i<3;i++) { for(j=0;j<3;j++) { printf(" %9d",x[i][j]); }printf("\n"); }printf("\n"); } return 0; }

専門家に質問してみよう