配列を使った複数の行列の逆行列を求める関数の作成

このQ&Aのポイント
  • C言語で、4次元正方行列の逆行列を求めるプログラムを配列を使って実装しています。このプログラムを複数の行列の逆行列を求める関数に拡張する方法を教えてください。具体的には、行列を配列で作成し、逆行列を求める掃き出し法を実装する方法を知りたいです。
  • 配列を使った4次元正方行列の逆行列を求めるプログラムを複数の行列に対応させる関数の実装方法を教えてください。現在は単位行列を作成し、掃き出し法を用いて逆行列を求めていますが、複数の行列に対応させるためにはどのように変更すればよいのでしょうか。
  • C言語で4次元正方行列の逆行列を求めるプログラムを作成していますが、複数の行列に対応する関数にする方法がわかりません。現在は配列を使用して行列を表現し、逆行列を求める掃き出し法を実装しています。複数の行列に対応するためにはどのように変更すればいいのでしょうか。
回答を見る
  • ベストアンサー

配列を戻り値にして逆行列を求める関数

#include(stdio.h) int main(){ double a[4][4]={{1,2,0,-1},{-1,1,2,0},{2,0,1,1},{1,-2,-1,1}}; //入力用の配列 double inv_a[4][4]; //ここに逆行列が入る double buf; //一時的なデータを蓄える int i,j,k; //カウンタ int n=4; //配列の次数 //単位行列を作る for(i=0;i<n;i++){ for(j=0;j<n;j++){ inv_a[i][j]=(i==j)?1.0:0.0; } } //掃き出し法 for(i=0;i<n;i++){ buf=1/a[i][i]; for(j=0;j<n;j++){ a[i][j]*=buf; inv_a[i][j]*=buf; } for(j=0;j<n;j++){ if(i!=j){ buf=a[j][i]; for(k=0;k<n;k++){ a[j][k]-=a[i][k]*buf; inv_a[j][k]-=inv_a[i][k]*buf; } } } } //逆行列を出力 for(i=0;i<n;i++){ for(j=0;j<n;j++){ printf(" %f",inv_a[i][j]); } printf("\n"); } } という、4次元正方行列の逆行列を求めるプログラムがあるのですが これを複数の行列の逆行列が求められる関数にする場合を教えてください・・行列は配列で作ってるのでよくわかりません、お願いします

  • shunti
  • お礼率32% (123/381)

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

  • ベストアンサー
  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.2

もともとのコードが正しければ(逆行列を求めるロジックに誤りがなければ)、 こんな感じでよいのではないかと思います。 #include <stdio.h> #define N (4) //配列の次数 void getInverseMatrix(double (*a)[N], double (*b)[N]) { double buf; //一時的なデータを蓄える int i, j, k; //カウンタ //単位行列を作る for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { b[i][j] = (i == j) ? 1.0 : 0.0; } } //掃き出し法 for (i = 0; i < N; i++) { buf = 1 / a[i][i]; for (j = 0; j < N; j++) { a[i][j] *= buf; b[i][j] *= buf; } for (j = 0; j < N; j++) { if (i != j) { buf = a[j][i]; for (k = 0; k < N; k++) { a[j][k] -= a[i][k] * buf; b[j][k] -= b[i][k] * buf; } } } } } void printMatrix(double (*a)[N]) { int i, j; for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { printf("%10.6f", a[i][j]); } putchar('\n'); } } int main(void) { double a[N][N] = { //入力用の配列 { 1, 2, 0, -1}, { -1, 1, 2, 0}, { 2, 0, 1, 1}, { 1, -2, -1, 1} }; double b[N][N] = { //入力用の配列 { 2, 0, -2, 3}, { -4, -1, 1, 1}, { 0, 3, -2, -1}, { 1, -1, 0, 4} }; double inv[N][N]; //ここに逆行列が入る printf("【行列a】\n"); printMatrix(a); getInverseMatrix(a, inv); printf("【行列aの逆行列】\n"); printMatrix(inv); printf("\n【行列b】\n"); printMatrix(b); getInverseMatrix(b, inv); printf("【行列bの逆行列】\n"); printMatrix(inv); return 0; }

shunti
質問者

お礼

ありがとうございます^o^このあたり勉強不足で・・・助かりました

その他の回答 (1)

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.1

> 複数の行列の逆行列が求められる関数 当該の複数行列は、例題と同じ4行4列ですか? 別の行数・列数にも対応する必要がありますか?

shunti
質問者

補足

あ、すいません全部4行4列でお願いします^^;

関連するQ&A

  • 逆行列のアルゴリズム

    現在逆行列を求めるアルゴリズムを勉強してるんですが、全然わかりません。 とあるサイトさんから逆行列を求めるソースを拝借させていただきました。 実際に2行2列の値を入れて手計算でプログラムを追っていったら23行目で対角成分に1を代入したり、33行目で対角成分以外の成分に0を代入しているのはわかるんですが、わかるのはその程度で、もっと詳しくアルゴリズムを教えていただきたいです。 わかりやすいサイトなどでも結構なんで教えていただけると助かります! よろしくおねがいします。 #include <stdio.h> 01:int main(void) 02:{ 03: 04: double exp_At[2][2]={{1,3},{2,1}}; //入力用の配列 05: double inv_exp_At[2][2]; //ここに逆行列が入る 06: double buf; //一時的なデータを蓄える 07: int i,j,k; //カウンタ 08: int num=2; //配列の次数 09: //単位行列を作る 10: for(i=0;i<num;i++) 11: { 12: for(j=0;j<num;j++) 13: { 14: inv_exp_At[i][j]=(i==j)?1.0:0.0; 15: } 16: } 17: /* 掃き出し法 */ 18: for(i=0; i<num; i++) /* 逆行列をexp(-At)求める */ 19: { 20: buf=1/exp_At[i][i]; 21: for(j=0; j<num; j++) 22: { 23: exp_At[i][j] *= buf; 24: inv_exp_At[i][j] *= buf; 25: } 26: for(j=0; j<num; j++) 27: { 28: if(i != j) 29: { 30: buf=exp_At[j][i]; 31: for(k=0; k<num; k++) 32: { 33: exp_At[j][k] -= exp_At[i][k] * buf; 34: inv_exp_At[j][k] -= inv_exp_At[i][k] * buf; 35: } 36: } 37: } 38: } 39://逆行列を出力 40: 41: printf("逆行列exp(-At)=\n"); 42: 43: for(i=0;i<num;i++) 44: { 45: for(j=0;j<num;j++) 46: { 47: printf(" %f",inv_exp_At[i][j]); 48: } 49: printf("\n"); 50: } 51:}

  • c言語 逆行列 掃き出し法 既約分数

    c言語初心者の者です。課題がででソースコードを書き、コマンドプロンプトで入力したら、「a.exeは動作が停止しました」と出ました。恐らくスタックを消費仕切っているのだと思いますが、改善する内容がわかりません。出来れば理由込みで詳しく改善点を教えてほしいです。できるだけ簡単なプログラムで作成をお願いします。 課題内容:4行4列の逆行列を計算するプログラムを作成せよ。但し、分数は既約分数とし、分母に「-」はつけない。掃き出し法を用いて解け。更に、ポインタや構造体や特別な関数を使用してはならない。 ソースコード: #include<stdio.h> int gcdf(int x, int y){ return(y == 0 ? x :gcdf(y,x%y)); /*最大公約数を求める*/ } int gcd(int a, int b){ return(a > b ? gcdf(a, b) : gcdf(a,a)); /*恐らくここも間違いの1つ、gcd(a,a)をどう                   なおせばいいか*/ } int main(void){ int buf[2]; /*データ保存*/ int i, j, k,g; /*カウンタ*/ int n = 4; /*配列の次数*/ int a[4][4][2] = {{{1,1},{2,1},{0,1},{1,2}}, /*問題の行列*/ {{0,1},{2,3},{1,1},{0,1}}, {{1,1},{0,1},{0,1},{-1,1}}, {{1,1},{0,1},{-1,2},{-1,1}}}; int inv_a[4][4][2] = {{{1,1},{0,1},{0,1},{0,1}}, /*単位行列*/ {{0,1},{1,1},{0,1},{0,1}}, {{0,1},{0,1},{1,1},{0,1}}, {{0,1},{0,1},{0,1},{1,1}}}; for(i = 0; i < n; i++){ buf[0] = a[i][i][1]; //分子 buf[1] = a[i][i][0]; //分母 for(j = 0; j < n; j++){ a[i][j][0] = buf[0] * a[i][j][0]; a[i][j][1] = buf[1] * a[i][j][1]; g = gcd(a[i][j][0], a[i][j][1]); a[i][j][0] = a[i][j][0] / g; a[i][j][1] = a[i][j][1] / g; //約分 inv_a[i][j][0] *= buf[0]; inv_a[i][j][1] *= buf[1]; g = gcd(inv_a[i][j][0], inv_a[i][j][1]); inv_a[i][j][0] = inv_a[i][j][0] / g; inv_a[i][j][1] = inv_a[i][j][1] / g; //約分 } for(j = 0; j < n; j++){ if(i != j) buf[0] = a[j][i][0]; buf[1] = a[j][i][1]; for(k = 0; k < n; k++){ a[j][k][0] = a[j][k][0] * a[i][k][1] * buf[1] - a[j][k][1] * a[i][k][0] * buf[0]; a[j][k][1] = a[j][k][1] * a[i][k][1] * buf[1]; g = gcd(a[j][k][0], a[j][k][1]); a[j][k][0] = a[j][k][0] / g; a[j][k][1] = a[j][k][1] / g; inv_a[j][k][0] = inv_a[j][k][0] * inv_a[i][k][1] * buf[1] - inv_a[j][k][1]* inv_a[i][k][0] * buf[0]; inv_a[j][k][1] = inv_a[j][k][1] * inv_a[i][k][1] * buf[1]; g = gcd(inv_a[j][k][0], inv_a[j][k][1]); inv_a[j][k][0] = inv_a[j][k][0] / g; inv_a[j][k][1] = inv_a[j][k][1] / g; }}} printf("1 2 0 1/2 \n 0 2/3 1 0 \n 1 0 0 -1 \n 1 0 -1/2 -1 \n の逆行列は以下の通り"); for(i = 0; i < n; i++){ /*逆行列出力*/ for(j = 0; j < n; j++){ if(inv_a[i][j][1] = 0){ inv_a[i][j][0] *= (-1); inv_a[i][j][1] *= (-1); /*分母のマイナスをプラスに*/ } /*分母が1の時に整数表示*/ if(inv_a[i][j][1] != 1) printf("%d/%d", inv_a[i][j][0],inv_a[i][j][1]); else printf("%d", inv_a[i][j][0]); } } return 0; }

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

  • 行列の積について

    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文のブロックの組み方がまずいのかなと思っていますが、これ以外だと、行列のレイアウトが崩れてしまいます どのように直したらいいのか、ご教示お願いします

  • 行列の計算【配列 関数】

    行列式を計算する関数をもちいてプログラムを見やすくしたいのですが、何回やっても値の渡し方がわかりません。 他にも逆行列のプログラムなどの渡し方も知りたいです。 以下が時ビンで考えたプログラムです。 #include <stdio.h> double det(double array[3][3]); int main( void ) { int i,j,k,n=3; double array[3][3],d; for(i=0;i<3;i++) { for(j=0;j<3;j++) { printf( "A[%d,%d]=",i+1,j+1); scanf( "%lf",&array[ i ][ j ] ); } } printf("det= %f \n",det(array[][])); return 0; } double det(double array[][]) { double array[3][3]; d=array[0][0]*array[1][1]*array[2][2]; d+=array[1][0]*array[2][1]*array[0][2]; d+=array[2][0]*array[0][1]*array[1][2]; d-=array[2][0]*array[1][1]*array[0][2]; d-=array[1][0]*array[0][1]*array[2][2]; d-=array[0][0]*array[2][1]*array[1][2]; return d; } よろしくお願いします。

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

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

  • LU分解を利用した逆行列のプログラム(Java)

    LU分解を利用した逆行列のプログラムが作れません… というか、作ったのですが実行するとエラーが出てしまいます(´Д`;) どこをどう直せばいいか、もしくはこのようにプログラムした方が効率がよい などのアドバイスどなたか下さい double a[][]={{2,5,4}, {2,3,-1}, {6,9,28}}; int N=a.length; double[][] s=new double[N][N]; for(int k=0; k<a[0].length-1; k++){ for(int i=k+1; i<N; i++){ s[i][k]=a[i][k]/a[k][k]; a[i][k]=s[i][k]; for(int j=k+1; j<N; j++){ a[i][j] -= s[i][k] * a[k][j]; } } } double[][] y=new double[N][N]; double[][] X=new double[N][N]; double[][] e=new double[N][N]; for(int i=0;i<N;i++){ for(int j=0;j<N;j++){ if(i==j){ e[i][j]=1; }else{ e[i][j]=0; } } } for(int i=0;i<N;i++){ y[1][i]=e[1][i]; for(int k=2;k<=N;k++){ for(int j=1;j<=N;j++){ y[k][i]=e[k][i]-s[k][j]*y[j][i]; } } X[N][i]=y[N][i]/a[N][N]; for(int k=N-1;k>=1;k--){ for(int j=k+1;j<=N;j++){ X[k][j]=(y[k][j]-s[k][j]*X[j][i])/a[k][k]; } } } for(int i=0;i<N;i++){ for(int j=0;j<N;j++){ System.out.printf(" %6.5f ", X[i][j] ); } System.out.println(""); }

  • C++についての質問です

    プログラミング初心者です 以下の通りに正方行列の積を求めるプログラムを作成したのですが、うまくいきません。 #include<stdio.h> #define DTM 20 void InputMatrix(double[][DTM], int, char); void PrintMatrix(double[][DTM], int, char); void MatrixMulti(double[][DTM], double[][DTM], double[][DTM], int); int main(void) { double matrixA[DTM][DTM]; double matrixB[DTM][DTM]; double matrixC[DTM][DTM]; int n; printf("正方行列の積を求めるプログラムです\n"); printf("正方行列の次元を入れてください(<=20):"); scanf_s("%d", &n); InputMatrix(matrixA, n, 'A'); InputMatrix(matrixB, n, 'B'); MatrixMulti(matrixA, matrixB, matrixC, n); printf("\n行列 C =A×B\n"); PrintMatrix(matrixC, n, 'C'); return 0; } void InputMatrix(double a[][DTM], int n, char ch) { int i, j; printf("行列 %cの入力\n", ch); for (i = 0; i < n;i++) { for (j = 0;j < n;j++) { printf("%c[%d][%d] =", ch, i + 1, j + 1); scanf_s("%lf", &a[i][j]); } } } void PrintMatrix(double a[][DTM], int n, char ch) { int i, j; printf("行列 %c の出力\n", ch); for (i = 0;i < n;i++) { for (j = 0;j < n;j++) { printf("%5.2f\t", a[i][j]); } printf("\n"); } } void MatrixMulti(double a[][DTM], double b[][DTM], double c[][DTM], int n) { int i, j, k; for (i = 0;i < n;i++) { for (j = 0;j < n;j++) { c[i][j] = 0; for (k = 0;k < n;k++) { c[i][j] =a[i][k] * b[k][j]; } printf("%5.2f\t",c[i][j]); } printf("\n"); } }

  • 数学の公式に沿った逆行列

     数学の公式に沿った2x2逆行列を作るという演習問題を解きたいのですが  下記のプログラムではdの値がおかしくなってしまいます。  何が悪いのか指摘していただけませんでしょうか。  よろしくお願いします。 // 20060414.cpp : コンソール アプリケーションのエントリ ポイントを定義します。 // #include "stdafx.h" #include <stdio.h> #include <stdlib.h> int _tmain(int argc, _TCHAR* argv[]) { int i,j ; double a[2][2] ; double b[2][2] ; double d ; for (i=0;i<2;i++){ for (j=0;j<2;j++){ printf("a%d%d = ?",i+1,j+1); scanf("%f",&a[i][j]); } } d = a[0][0]*a[1][1]-a[0][1]*a[1][0]; if (d==0.0){ printf("行列式は正則でない。\n"); exit(1); } b[0][0] = a[1][1]/d; b[0][1] = -a[0][1]/d; b[1][0] = -a[1][0]/d; b[1][1] = a[0][0]/d; for (i=0;i<2;i++){ for (j=0;j<2;j++){ printf("b%d%d = %f\n",i+1,j+1,b[i][j]); } } scanf("%d",d); return 0; }

  • doubleからfloatにすると表示が変になる

    しょうもない質問ですいません。 下記のC言語の行列積のコードでは行列の変数をdoubleとしていますが、これをfloatに全て置き換えると、printfで表示させる結果がバグってしまいます。 原因は何でしょうか? 最近ひさしぶりにC言語を触ったので、しょうもないところでつまずきました。 お願いします。 ----------------------------------------- #include <stdio.h> #include <stdlib.h> #define N 10 //N次の正方行列まで扱えるようにする void matrixmultiply(int n,double a[N][N],double b[N][N],double c[N][N]); int main(int argc, char** argv) { int i,j,n; double A[N][N],B[N][N],C[N][N]; FILE *readin1,*readin2; /*行列の値が書き込まれたファイルを開く*/ if((readin1=fopen("a.dat","r"))==NULL) { printf("a.datを開けません\n"); exit(1); } if((readin2=fopen("b.dat","r"))==NULL) { printf("b.datを開けません\n"); exit(1); } printf("行列の次数を入力してください\n"); scanf("%d",&n); printf("%d次の正方行列の掛け算を行います\n\n",n); /*ファイルから数値を読み込み、配列に代入する*/ for(i=0;i<n;i++) { for(j=0;j<n;j++) { fscanf(readin1,"%lf",&A[i][j]); fscanf(readin2,"%lf",&B[i][j]); } } matrixmultiply(n,A,B,C); //関数を呼び出し行列の掛け算を行う。 /*結果を表示する*/ printf("計算結果\n"); for(i=0;i<n;i++) { for(j=0;j<n;j++) { printf("%lf ",C[i][j]); } printf("\n"); } fclose(readin1); fclose(readin2); return 0; } /*掛け算を行う行列2つと、結果を入れる行列を引数として受け取る。*/ void matrixmultiply(int n,double a[N][N],double b[N][N],double c[N][N]) { int i,j,k; /*受け取った2つの行列の掛け算を行う。*/ for(i=0;i<n;i++) { for(j=0;j<n;j++) { for(k=0;k<n;k++) { c[i][j]+=a[i][k]*b[k][j]; } } } }

専門家に質問してみよう