• ベストアンサー

行列式のプログラムでのループがわかりません。

行列式を求めるプログラムを考えていて、一応はちゃんと答えがでるのですが、 ループを使って計算させようとしたのですがイマイチわかりません。 #include <stdio.h> main() {     int a[3][3]={{1,2,2},{-1,5,3},{2,0,1}};     int i,j,n;     for(i=0;i<3;i++)     {          for(j=0;j<3;j++)              printf("%3d",a[i][j]);              printf("\n");     }     n=a[0][0]*(a[1][1]*a[2][2]-a[1][2]*a[2][1])      -a[1][0]*(a[0][1]*a[2][2]-a[0][2]*a[2][1])      +a[2][0]*(a[0][1]*a[1][2]-a[0][2]*a[1][1]);     printf("この行列の行列式は \n");     printf("%d \n",n); } 1 2 2 -1 5 3 2 0 1 という行列式です。 nの処理をループを使うとどう書いたらいいでしょうか? これはたまたま3行3列だからひとつひとつ指定して計算できますが これが4行4列とかだったら絶対ループ使わなきゃ面倒ですからね~。 とりあえず3行3列のが理解できたらいいとは思うのですがなかなか複雑で難しいですね。

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

  • ベストアンサー
回答No.8

今日は、usui323さん。 私の方法は、#7で二つ目に紹介されているサイトと本質的に同じですね。 定義から求めているので当たり前ですが。 ですので、概略に留めさせてもらいます。  nは、行列の次数、fact_nはnの階乗とする。  junは順列を格納する符号無し文字型配列  GetPermutate i番目の順列を返す関数。iは1以上fact_n以下  Sign 順列の符号を返す関数  A(i,j) 行列の(i,j)成分  全角空白でインデントしてます  det=0;  for (cnt1=1;cnt1<=fact_n;cnt1++)  {    GetPermutate(cnt1,jun);    term = Sign(jun);    for (cnt2=0;cnt2<n;cnt2++)      termproduct *= A(cnt2+1,jun(cnt2));    det += termproduct;  }

usui323
質問者

お礼

回答ありがとうございました。 あまりプログラムに慣れていないので理解するのが大変でしたが、大変参考になりました。

その他の回答 (8)

回答No.9

#8の訂正 誤 termproduct *= A(cnt2+1,jun(cnt2)); 正 termproduct *= A(cnt2+1,jun[cnt2]);

  • hofuhofu
  • ベストアンサー率70% (336/476)
回答No.7

#2で書いた場所はここです http://mukun_mmg.tripod.co.jp/mmg/bncpp/al047.html ちなみにこのままでは1行1列からn行n列への対角線上に0がでてきた場合はエラーが発生します。 再帰を使ったプログラムがあったので載せておきます。 ここの「おまけプログラム」にある「行列式を定義に従って求める」です。 http://www.altum.jp/math/exp1/

usui323
質問者

お礼

回答ありがとうございました。 大変参考になりました。m(-_-)m

  • absurd0rt
  • ベストアンサー率23% (4/17)
回答No.6

下のコードをエクセルに貼り付け、 "A1"=1,"B1"=2,"C1"=2 "A2"=-1,"B2"=5,"C2"=3 "A3"=2,"B3"=0,"C3"=1 と打ち下のコードを実行すれば"行列式"がでます。 ただVBですし、例外処理をすっぽかして作ってあります。 作ってて正攻法の方が絶対にいいかなと思いました。 参考程度にお願いします。 Private Sub CommandButton1_Click()   '*GYAKU   Dim ArrayA() As Double   Dim ArrayL() As Double   Dim ArrayR() As Double   Dim InvMatrix() As Double   Dim ArrayB() As Double   Dim TempB() As Double   Dim lngCnt1 As Long   Dim lngCnt2 As Long   Dim lngCnt3 As Long   Dim lngCnt4 As Long   Dim lngNCount As Long   Dim lngGyoShiki As Long   '初期設定   For lngCnt1 = 1 To 100     If IsEmpty(Worksheets("Sheet1").Cells(lngCnt1, 1)) = True Then       Exit For     End If   Next lngCnt1   lngNCount = lngCnt1 - 1   If lngNCount < 1 Then     Exit Sub   End If   ReDim ArrayA(lngNCount, lngNCount)   ReDim ArrayL(lngNCount, lngNCount)   ReDim ArrayR(lngNCount, lngNCount)   ReDim InvMatrix(lngNCount, lngNCount)   ReDim ArrayB(lngNCount)   ReDim TempB(lngNCount)   '初期値   For lngCnt1 = 1 To lngNCount     For lngCnt2 = 1 To lngNCount       ArrayA(lngCnt1, lngCnt2) = Worksheets("Sheet1").Cells(lngCnt1, lngCnt2)     Next lngCnt2   Next lngCnt1   'Main   For lngCnt1 = 1 To lngNCount     For lngCnt2 = 1 To lngNCount       If lngCnt2 = lngCnt1 Then         ArrayB(lngCnt2) = 1       Else         ArrayB(lngCnt2) = 0       End If     Next lngCnt2     'STEP1 行列Rを作る     For lngCnt2 = 1 To lngNCount       For lngCnt3 = 1 To lngNCount         ArrayR(lngCnt2, lngCnt3) = ArrayA(lngCnt2, lngCnt3)         TempB(lngCnt2) = ArrayB(lngCnt2)       Next lngCnt3     Next lngCnt2     For lngCnt2 = 1 To lngNCount       For lngCnt3 = 1 To lngNCount         If lngCnt3 <> lngCnt2 Then           ArrayL(lngCnt3, lngCnt2) = ArrayR(lngCnt3, lngCnt2) / ArrayR(lngCnt2, lngCnt2)           For lngCnt4 = lngCnt2 To lngNCount             ArrayR(lngCnt3, lngCnt4) = ArrayR(lngCnt3, lngCnt4) - ArrayL(lngCnt3, lngCnt2) * ArrayR(lngCnt2, lngCnt4)           Next lngCnt4           TempB(lngCnt3) = TempB(lngCnt3) - ArrayL(lngCnt3, lngCnt2) * TempB(lngCnt2)         End If       Next lngCnt3     ArrayL(lngCnt2, lngCnt2) = 1     Next lngCnt2     'STEP2 逆行列AAを求める     For lngCnt2 = 1 To lngNCount       InvMatrix(lngCnt2, lngCnt1) = TempB(lngCnt2) / ArrayR(lngCnt2, lngCnt2)     Next lngCnt2   Next lngCnt1   'STEP3 行列式   lngGyoShiki = 1   For lngCnt1 = 1 To lngNCount     lngGyoShiki = lngGyoShiki * ArrayR(lngCnt1, lngCnt1)   Next lngCnt1   '表示   Worksheets("Sheet1").Cells(lngNCount * 1 + 2, 1) = "逆行列"   For lngCnt1 = 1 To lngNCount     For lngCnt2 = 1 To lngNCount       Worksheets("Sheet1").Cells(lngCnt1 + (lngNCount * 1 + 2), lngCnt2) = InvMatrix(lngCnt1, lngCnt2)     Next lngCnt2   Next lngCnt1   Worksheets("Sheet1").Cells(lngNCount * 2 + 4, 1) = "固有値"   For lngCnt1 = 1 To lngNCount     Worksheets("Sheet1").Cells((lngNCount * 2 + 4) + 1, lngCnt1) = ArrayR(lngCnt1, lngCnt1)   Next lngCnt1   Worksheets("Sheet1").Cells(lngNCount * 2 + 7, 1) = "行列式"   Worksheets("Sheet1").Cells(lngNCount * 2 + 8, 1) = lngGyoShiki   '後始末   Erase ArrayA   Erase ArrayL   Erase ArrayR   Erase InvMatrix   Erase ArrayB   Erase TempB End Sub

usui323
質問者

お礼

回答ありがとうございます。 VBですか。VBは授業でとりあつかっていないので 全然わからないのですが、こんなに複雑になるんですね。 詳細なプログラムまで書いていただきありがとうございました。

回答No.5

私は10次までの行列式計算を行うプログラムを作っています。別にそれ以上ができないというわけではないですが、項数が多い(10次の場合で約360万項)ので10次で切っているだけです。 で、プログラムはC++でテンプレートを使っていますし、処理内容は行列式の定義にきちんと則った(順列計算を使った)やり方です。 このへんが、理解できるという事なら、プログラムの所在をお知らせします。

usui323
質問者

お礼

回答ありがとうございます。 一応問題解決しました。 10次ですか、すごいですね。 100%理解できるというわけではありませんが、参考の為教えてくれるとありがたいです。

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

No.2の方のご回答のように、ガウスの消去法を使う方法があると思います。 #include <stdio.h> #include <math.h> #define N 5 void main() { double X[N][N] = { { 1.0, 6.0, 4.0, 3.0, 9.0}, { 2.0, 1.0, 8.0, 6.0, 7.0}, { 3.0, 7.0, 1.0, 9.0, 5.0}, { 4.0, 2.0, 5.0, 1.0, 3.0}, { 5.0, 8.0, 9.0, 4.0, 1.0}, }; double A = 1.0; int i, j, k; for (i=N-1; i>=0; i--) { for (j=i-1; j>=0; j--) { for (k=0; k<i; k++) { X[j][k] -= X[i][k] * X[j][i] / X[i][i]; } } A *= X[i][i] * pow(-1, i+i); } printf("%f\n", A); } こんな感じになると思います。(とりあえず、この例では正解が得られるようですが、間違いがあるかもしれません。間違っていたらごめんなさい。)

  • absurd0rt
  • ベストアンサー率23% (4/17)
回答No.3

行列式にしろ、固有値にしろ対角行列に変換さえしてしまえば楽に求められるものです。そうすれば4行4列など問題ではありません。 プログラムは気が向いたらヒントくらい書くかもしれませんがあまり期待しないでください。

usui323
質問者

お礼

回答ありがとうございました。 問題解決しました。

  • hofuhofu
  • ベストアンサー率70% (336/476)
回答No.2

とあるメールマガジンのバックナンバーにn行n列の行列式を求めるサンプルプログラムがありました。 Gaussの消去法を使って出す方法ですが、割と機械的に処理できているようです。 計算はdoubleで行っていました。 まったく誤差を出さないようにと、すべてintでしようとすると、かなり手間が増えそうな感じです。

usui323
質問者

お礼

回答ありがとうございます。 問題解決しました。

  • jmh
  • ベストアンサー率23% (71/304)
回答No.1

こんな公式があったような気がします: det(A)=Σ(-1)^(i-1)×(Aの(i,1)成分)    ×det(Aから第i行と第1列を取り除いた行列)  (Σはi=1~Aの次数) これを使って、行列の次数を下げていく再帰を書いたらできるかもしれないです。

usui323
質問者

お礼

回答ありがとうございました。 問題解決しました。

関連するQ&A

  • 行列をべき乗させるプログラム

    2行2列を5乗させるプログラムを作って、一応できたつもりだったんですが結果が合いません・・・ 何かヒントでもいいのでわかる方いらっしゃいましたらよろしくお願いします。 <プログラム> #include <stdio.h> #define N 2 int A[N][N]; int A_NEW[N][N]; int A_5[N][N]; /* 行列Aを5乗したもの */ int main() { int i,j,k,l; /* 2行2列の係数行列Aの成分を入力 */ printf("係数行列Aを%d行%d列で入力してください\n", N, N); for( i=0; i<N; i++) { for( j=0; j<N; j++) { printf("A[%d][%d]=", i+1, j+1); scanf("%d", &A[i][j]); } } for(i=0; i<N; i++) /* A_NEW=A*Aの計算 */ { for(j=0; j<N; j++) { for(k=0; k<N; k++) { A_NEW[i][j] += A[i][k] * A[k][j]; } } } for(l=0; l<3; l++) { for(i=0; i<N; i++) /* A_5の計算 */ { for(j=0; j<N; j++) { for(k=0; k<N; k++) { A_5[i][j] += A_NEW[i][k] * A[k][j]; } } } for(i=0; i<N; i++) { for(j=0; j<N; j++) { A_NEW[i][j] = A_5[i][j]; } } } printf("A_5=\n"); /* 出力 */ for( i=0; i<N; i++) { for( j=0; j<N; j++) { printf("%d ", A_5[i][j]); } printf("\n"); } } <入力例> A= 1 3 2 1 <期待する結果> A= 241 303 202 241 <このプログラムの結果> 406 498 332 406

  • 3行3列の行列 A に対して、Aの2乗, Aの3乗 を求めよ。

    3行3列の行列 A に対して、Aの2乗, Aの3乗 を求めよ。 という問題で #include <stdio.h> #define N 3 int A[N][N]; int A_2[N][N]; /* 行列Aを2乗したもの */ int A_3[N][N]; /* 行列Aを3乗したもの */ int main() { int i,j,k,l; /* 3行3列の係数行列Aの成分を入力 */ printf("係数行列Aを%d行%d列で入力してください\n", N, N); for( i=0; i<N; i++) { for( j=0; j<N; j++) { printf("A[%d][%d]=", i+1, j+1); scanf("%d", &A[i][j]); } } ここまでがあたえられえているのですが、単純にA_2=A×Aとしてみたのですが、セグメントエラーが出てしまいうまく出力できませんでした。 A_2とA_3の計算方法とあたえられているプログラムの動作を教えてください。 よろしくお願いします

  • 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言語を用いた45×45の逆行列の表示について・・・・。。

    次のプログラムを動かすと逆行列を求めることができます。 10×10の計算までは、スムーズに計算する事ができたのですが、 私が知りたい45×45の行列の計算になるとなぜかうまくいきません。 そこでみなさんにお聞きしたいのは、計算がうまくいかない理由がプログラムにあるのか、単にPCの限界なのか、それ以外なのか。みなさんからアドバイスをいただけないでしょうか? ※下のプログラム、見づらくてすいません。 #include <stdio.h> #define N 10 /* 元の数 */ #define N2 2*N /* プロトタイプ宣言 */ void Print(int k); /* 大域変数 */ double a[N][N2]= {/* 行列 Aおよび単位行列 */ { ここに45×45の正則行列&45×45の単位行列を入れます・・・。。 }; int main(void) { double d; int i,j,k; for (k=0;k<=N-1;k++) { Print(k); for(i=0;i<=N-1;i++) { if(i!=k) { d=a[i][k]/a[k][k]; for (j=k+1;j<=N2-1;j++) a[i][j]=a[i][j]-a[k][j]*d; a[i][k] = 0.0; } } d=a[k][k]; for (j=k;j<=N2-1;j++) a[k][j]=a[k][j]/d; } Print(N); } void Print(int k) { int i,j; printf("\n ステップ %d \n",k); /* 小見出し */ for(i=0;i<=N-1;i++) { /* 第i行を印刷 */ for(j=0;j<=N-1;j++) printf("%6.4f,",a[i][j]); printf(" : "); for(j=N;j<=N2-1;j++) printf("%6.4f,",a[i][j]); printf("\n"); } }

  • 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); }

  • 行列の積を関数を使って求める・・?

    2つの行列の行と列を入力し、積を計算するプログラムを関数を使って書きたいのですが、上手く行きません。どこをどのように直したらよいか教えてください!お願いします!! 以下が私が書いたプログラムです。 #include<stdio.h> #define NUMBER 10 int first(int x1,int x2,int y1,int y2,int i,int j,int k) { int a[NUMBER][NUMBER] = {0}; int b[NUMBER][NUMBER] = {0}; int c[NUMBER][NUMBER] = {0}; do{ printf("2つの行列の行と列を入力してください\n"); scanf("%d", &x1); scanf("%d", &x2); scanf("%d", &y1); scanf("%d", &y2); if(x1 != y2){ printf("行列の積は計算できません\n"); } }while(x1 != y2); printf("行列Aの要素を入力してください\n"); for(i=0; i<x1; i++){ for(j=0; j<x2; j++) scanf("%d", &a[i][j]); } printf("行列Bの要素を入力してください\n"); for(j=0; j<y1; j++){ for(k=0; k<y2; k++) scanf("%d", &b[j][k]); } } int second(int x1,int x2,int y1,int y2,int i,int j,int k) { int a[NUMBER][NUMBER] = {0}; int b[NUMBER][NUMBER] = {0}; int c[NUMBER][NUMBER] = {0}; for(i=0; i<x1; i++){ for(k=0; k<y2; k++){ for(j=0; j<x2; j++) c[i][k] = c[i][k] + a[i][j]*b[j][k]; } } for(i=0; i<x2; i++){ for(k=0; k<y2; k++) printf("%3d", c[i][k]); printf("\n"); } } int main(void) { int a[NUMBER][NUMBER] = {0}; int b[NUMBER][NUMBER] = {0}; int c[NUMBER][NUMBER] = {0}; printf("行列の積を計算します\n %d\n", first(x1,x2,y1,y2,i,j,k)); printf("行列Aと行Bの積は\n %3d",second(x1,x2,y1,y2,i,j,k)); }

  • 行列の積について

    3行3列の行列AとB、およびその和と積を表示するものです #include <stdio.h> int main (void) { int i,j,k; double a[3][3] = {{2.4, 5.5, -8.5},{0.8, 3.7, 1.1},{3.5, -9.1, 2.6}}; double b[3][3] = {{-5.1, 9.8, 2.3},{-4.1, 0.2, -0.3},{3.3, 6.1, -1.3}}; double c[3][3] = {0}; printf(" 行列A\n"); for (i = 0; i < 3; i++){ for (j = 0; j < 3; j++) printf("%5.1f", a[i][j]); printf("\n"); } printf("\n 行列B\n"); for (i = 0; i < 3; i++){ for (j = 0; j < 3; j++) printf("%5.1f", b[i][j]); printf("\n"); } printf("\n 行列A+B\n"); for (i = 0; i < 3; i++){ for (j = 0; j < 3; j++) c[i][j] = a[i][j] + b[i][j]; } for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) printf("%5.1f", c[i][j]); printf("\n"); } for (i=0; i<3 ; i++){ for (j=0; j<3; j++) for (k=0; k<3; k++) c[i][j] =c[i][j]+ a[i][k]* b[k][j]; } printf("\n 行列AB\n"); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) printf("%7.2f", c[i][j]); printf("\n"); } return 0; } これだと積だけが異なった値が出てしまいます。 試しに、積の部分だけで組んでみると正しい答えが出ました。 for文のブロックの組み方がまずいのかなと思っていますが、これ以外だと、行列のレイアウトが崩れてしまいます どのように直したらいいのか、ご教示お願いします

  • 行列の積を計算するプログラムがうまくいきません

    どこが間違っているのかわかる方お願いします ・行列A,Bはファイルから読み込む ・行列A,Bの積Cの計算には関数を用いる #include<stdio.h> #define ROW 10 #define COL 10 void MatrixProduct(int a[][COL],int b[][ROW],int c[][ROW],int n,int m ) { int i,j,k; for(i=0;i<n;i++){ for(j=0;j<n;j++){ c[i][j]=0; } } for(i=0;i<n;i++){ for(j=0;j<n;j++){ for(k=0;k<m;k++){ c[i][j]=c[i][j]+a[i][k]*b[k][j]; } } } } int main(void) { FILE *fp1,*fp2; char fname1[64],fname2[64]; int a[ROW][COL],b[ROW][COL],c[ROW][COL],n,m; int i,j,k; printf("Input file name ?"); scanf("%s",fname1); printf("Output file name ?"); scanf("%s",fname2); fp1=fopen(fname1,"r"); fp2=fopen(fname2,"w"); fscanf(fp1,"%d %d",&n,&m); MatrixProduct(a,b,c,n,m); for(i=0;i<n;i++){ for(j=0;j<n;j++){ fprintf(fp2,"%3d",c[i][j]); } fprintf(fp2,"\n"); } fclose(fp1); fclose(fp2); return(0); } fp1 3 4 1 2 3 4 2 3 4 5 3 4 5 6 1 2 3 2 3 4 3 4 5 4 5 6

  • ピラミッド表示プログラム。

    ピラミッドを表示させるプログラムを考えています。 例えば3段の場合   *  *** ***** っというような表示です。 #include <stdio.h> void spira(int n); main() { int a; printf("段数は:"); scanf("%d",&a); spira(a); } void spira(int n) { int i,j=1,a,b,k; for(a=n;a>0;a--){ for(b=a-1;b<=n;b--){ printf(" "); } k=(j-1)*2+1; for(i=1;i<=k;i++){ printf("*"); } j++; printf("\n"); } } このように考えてみたのですが、無限ループになって表示できません。 どこが悪いでしょうか? 無限ループの原因はどうやったら解消されるでしょうか?

  • プログラム

    下のようなプログラムを作ったのですが、10進2進変換をj=n>>2&1の部分にあるようなビットシフトではなく、 for(i=1;i<8;i++){printf("bit[%d]=%d\n",i,n%2);n=n/2;}に変えて剰余計算で行うプログラムにしたいのですが、分かる方がいましたら教えて下さい。お願いします。 #include <stdio.h> int main(void) { int i,j,n; i=2; printf("数字を入力="); scanf("%d",&n); printf("Dec=%d\n",n); printf("heX=0x%x\n",n); j=n>>2&1; printf("bit[%d]=%d\n",i,j); return(0); }

専門家に質問してみよう