- ベストアンサー
行列式のプログラムでのループがわかりません。
行列式を求めるプログラムを考えていて、一応はちゃんと答えがでるのですが、 ループを使って計算させようとしたのですがイマイチわかりません。 #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列のが理解できたらいいとは思うのですがなかなか複雑で難しいですね。
- usui323
- お礼率84% (351/415)
- C・C++・C#
- 回答数9
- ありがとう数9
- みんなの回答 (9)
- 専門家の回答
質問者が選んだベストアンサー
今日は、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; }
その他の回答 (8)
- graphaffine
- ベストアンサー率23% (55/232)
#8の訂正 誤 termproduct *= A(cnt2+1,jun(cnt2)); 正 termproduct *= A(cnt2+1,jun[cnt2]);
- hofuhofu
- ベストアンサー率70% (336/476)
#2で書いた場所はここです http://mukun_mmg.tripod.co.jp/mmg/bncpp/al047.html ちなみにこのままでは1行1列からn行n列への対角線上に0がでてきた場合はエラーが発生します。 再帰を使ったプログラムがあったので載せておきます。 ここの「おまけプログラム」にある「行列式を定義に従って求める」です。 http://www.altum.jp/math/exp1/
お礼
回答ありがとうございました。 大変参考になりました。m(-_-)m
- absurd0rt
- ベストアンサー率23% (4/17)
下のコードをエクセルに貼り付け、 "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
お礼
回答ありがとうございます。 VBですか。VBは授業でとりあつかっていないので 全然わからないのですが、こんなに複雑になるんですね。 詳細なプログラムまで書いていただきありがとうございました。
- graphaffine
- ベストアンサー率23% (55/232)
私は10次までの行列式計算を行うプログラムを作っています。別にそれ以上ができないというわけではないですが、項数が多い(10次の場合で約360万項)ので10次で切っているだけです。 で、プログラムはC++でテンプレートを使っていますし、処理内容は行列式の定義にきちんと則った(順列計算を使った)やり方です。 このへんが、理解できるという事なら、プログラムの所在をお知らせします。
お礼
回答ありがとうございます。 一応問題解決しました。 10次ですか、すごいですね。 100%理解できるというわけではありませんが、参考の為教えてくれるとありがたいです。
- kary
- ベストアンサー率55% (10/18)
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)
行列式にしろ、固有値にしろ対角行列に変換さえしてしまえば楽に求められるものです。そうすれば4行4列など問題ではありません。 プログラムは気が向いたらヒントくらい書くかもしれませんがあまり期待しないでください。
お礼
回答ありがとうございました。 問題解決しました。
- hofuhofu
- ベストアンサー率70% (336/476)
とあるメールマガジンのバックナンバーにn行n列の行列式を求めるサンプルプログラムがありました。 Gaussの消去法を使って出す方法ですが、割と機械的に処理できているようです。 計算はdoubleで行っていました。 まったく誤差を出さないようにと、すべてintでしようとすると、かなり手間が増えそうな感じです。
お礼
回答ありがとうございます。 問題解決しました。
- jmh
- ベストアンサー率23% (71/304)
こんな公式があったような気がします: det(A)=Σ(-1)^(i-1)×(Aの(i,1)成分) ×det(Aから第i行と第1列を取り除いた行列) (Σはi=1~Aの次数) これを使って、行列の次数を下げていく再帰を書いたらできるかもしれないです。
お礼
回答ありがとうございました。 問題解決しました。
関連する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
- ベストアンサー
- C・C++・C#
- 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・C++・C#
- 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・C++・C#
- 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)); }
- 締切済み
- C・C++・C#
- 行列の積について
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文のブロックの組み方がまずいのかなと思っていますが、これ以外だと、行列のレイアウトが崩れてしまいます どのように直したらいいのか、ご教示お願いします
- ベストアンサー
- C・C++・C#
- 行列の積を計算するプログラムがうまくいきません
どこが間違っているのかわかる方お願いします ・行列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
- ベストアンサー
- C・C++・C#
- ピラミッド表示プログラム。
ピラミッドを表示させるプログラムを考えています。 例えば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"); } } このように考えてみたのですが、無限ループになって表示できません。 どこが悪いでしょうか? 無限ループの原因はどうやったら解消されるでしょうか?
- ベストアンサー
- C・C++・C#
- プログラム
下のようなプログラムを作ったのですが、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); }
- 締切済み
- C・C++・C#
お礼
回答ありがとうございました。 あまりプログラムに慣れていないので理解するのが大変でしたが、大変参考になりました。