• ベストアンサー

部分行列の抜き出し(C言語)

部分行列の抜き出し(C言語) ある行列から、任意の部分行列を抜き出すような関数を作りたいのですが、わからないので手助けをお願いしたいです。 たとえば4行4列の行列Aがあった場合、その2行2列、2行3列、3行2列、3行3列目の 4つの(2行2列の)要素を抜き出すような関数です。 枠組みは出来ているので載せておきます。 #include <stdio.h> #include <stdlib.h> #include <math.h> typedef struct matrix{ double *data; int size[2]; }MATRIX; MATRIX create_matrix(int m,int l,int a); //行列の作成 void print_matrix(MATRIX A); //行列の表示 MATRIX submatrix(MATRIX matrix_A,int m,int n,int l,int k); //任意の部分行列の抜き出し int main(int argc,char **argv) { //構造体の初期化 MATRIX matrix_A={NULL,NULL,NULL}; MATRIX matrix_B={NULL,NULL,NULL}; MATRIX matrix_C={NULL,NULL,NULL}; int m=0; //行列の行 int l=0; //行列の列 int a=1; //要素 double det=0; //行列計算 //行列Aの作成 m=4;//行 l=4;//列 matrix_A = create_matrix( m, l, a); //関数 matrix_C = submatrix(matrix_A,2,2,3,3); //行列結果出力 printf("\n\tmatrix input"); print_matrix(matrix_A); printf("\n\tmatrix output"); print_matrix(matrix_C); //行列の開放 free(matrix_A.data); matrix_A.data=NULL; free(matrix_C.data); matrix_C.data=NULL; printf("終了!\n\n"); return 0; } MATRIX create_matrix(int m,int l,int a) { MATRIX matrix_A={NULL,NULL,NULL}; int i=0; //サイズの確保 行;size[0] 列;size[1] matrix_A.size[0]=m; matrix_A.size[1]=l; //メモリの確保 matrix_A.data=(double *)malloc(sizeof(double)*matrix_A.size[0]*matrix_A.size[1]); if(matrix_A.data == NULL){ printf("メモリ確保失敗!![matrix_A]\n"); exit(1); } //行列Aの作成 for(i=0; i<((matrix_A.size[0])*(matrix_A.size[1])) ;i++){ *(matrix_A.data+i)=a+i; } return(matrix_A); } /*行列の表示*/ void print_matrix(MATRIX matrix_A) { int i=0; int j; //行 int k; //列 printf("\n行列の表示\n"); //行列Aのプリント for(j=0;j<matrix_A.size[0];j++){ for(k=0;k<matrix_A.size[1];k++){ printf("%f\t",*(matrix_A.data+k*matrix_A.size[0]+j)); } printf("\n"); } return; } MATRIX submatrix(MATRIX matrix_A,int m,int n,int l,int k) { MATRIX matrix_C = {NULL,NULL,NULL}; int i,j; //サイズの確保 行;size[0] 列;size[1] matrix_C.size[0]=l-m+1; matrix_C.size[1]=k-n+1; //メモリの確保 matrix_C.data=(double *)malloc(sizeof(double)*matrix_C.size[0]*matrix_C.size[1]); if(matrix_C.data == NULL){ printf("メモリ確保失敗!![matrix_C]\n"); exit(1); } //任意の部分行列の抜き出し (ここがわかりません。) } よろしくお願いします。

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

  • ベストアンサー
  • yama5140
  • ベストアンサー率54% (136/250)
回答No.3

>抜き出すような関数  を作る前に、「初期化」「出力」関数の動作確認をしてみたら、如何でしょう?。  (その関数の中で、_A を使うのは間違いの元ですよ)  No.2 さんも指摘していますが、★の方がよいかと・・。  30年以上昔のことで記憶が定かでないですが、Fortran77 だって★の「入り方(メモリの並び)」だったような。 2つの関数の動作確認ができたら、これまた No.1 さんが言われるように >そしてそれは print_matrix でやっていることと同じ  に、「抜き出すような関数」を作るだけ、と思います。  例)for( j = m; j <= l; j++ ){   // m ↓ l     for( k = n; k <= k; k++ ){  // n → k      左辺(ちょっと考えて) = 右辺(そのまんま) #include <stdio.h> #include <stdlib.h> typedef struct{  double *data;  int iGyouSize; // [0] とかより分かり易いかと・・2つしかないんだし。  int iRetuSize; }MATRIX; void print_matrix( MATRIX matrix ) {  int j; // 行  int k; // 列  printf( "\n行列の表示\n" );  for( j = 0; j < matrix.iGyouSize; j++ ){ // m ↓ l   for( k = 0; k < matrix.iRetuSize; k++ ){ // n → k    printf( "%lf\t", *( matrix.data + k * matrix.iGyouSize + j ) ); // 質問者様 //   printf( "%lf\t", *( matrix.data + k + matrix.iRetuSize * j ) ); // お勧め★   }   printf( "\n" );  } } MATRIX create_matrix( int m, int l, int a ) {  MATRIX matrix;  int i;  matrix.iGyouSize = m;  matrix.iRetuSize = l;  matrix.data = (double *)malloc( sizeof(double) * matrix.iGyouSize * matrix.iRetuSize );  if( NULL == matrix.data ){   printf( "メモリ確保失敗!![matrix]\n" );   exit( 1 );  }  for( i = 0; i < ( matrix.iGyouSize * matrix.iRetuSize ); i++ ) *( matrix.data + i ) = (double)( a + i );  return( matrix ); } int main( void ) {  int m = 4; // 行列の行  int l = 4; // 行列の列  int a = 1; // 要素  MATRIX matrix_A;  matrix_A = create_matrix( m, l, a );  print_matrix( matrix_A );  free( matrix_A.data );  return( 0 ); } 注:インデントに全角空白を用いています。コピペ後、タブに一括変換して下さい。

a0672113
質問者

お礼

丁寧な解答ありがとうございました。 なんとか解決することができました!

その他の回答 (3)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

いや, FORTRAN や Fortran では C と異なり前の方の添字が先にまわります>#3. つまり A(0:1, 0:1) は A(0, 0), A(1, 0), A(0, 1), A(1, 1) の順に配置されます.

a0672113
質問者

お礼

なんとか解決することができました! 本当にありがとうございました。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

for ループは 2重でいけます. m, n, l, k は (ここでは) 固定されていることに注意. i と j を (適切な範囲で) 2重ループでまわしながら, c[i][j] = a[m+i][n+j]; に相当する文を書くだけです. ちなみにもっと姑息に行けばループは 1つですみます. あとたぶん蛇足だけど, データの配置順序が普通の C の順序と逆っぽい気がする. 今は A の (j, k) 要素を *(matrix_A.data+k*matrix_A.size[0]+j) で取り出してるけど, 普通の C の順序では *(matrix_A.data+j*matrix_A.size[1]+k) となるはず. いや, Fortran が念頭にあるならいいけど.

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

普通の 2次元配列だと思えば c[i][j] = a[m+i][n+j]; ですよね. これを「1次元的にアクセスする」だけです. そしてそれは print_matrix でやっていることと同じ. なお, MATRIX matrix_A={NULL,NULL,NULL}; という初期化は間違いです. 2つ目, 3つ目の NULL は int data[2] に対する初期化データになりますが, NULL は「ポインタと解釈すべき」であり, それを使って int を初期化するのはおかしいです (NULL を 0 で定義する処理系もあり, その場合には結果的に問題ないとはいえ論理的にはおかしい).

a0672113
質問者

補足

素早いご指摘ありがとうございます。初期化に関しては修正してみますね。 関数部分なのですが、1次元的に考えるという点は理解できるのですが、どうプログラムを組めばいいか未だにわかりません。 for文って4つ必要ですか??自分なりに考えたプログラムだと4つ 使うんですが、実行してみるとエラーこそでないですが、抜き出した 行列の要素が全部同じになっちゃて困っています。

関連するQ&A

  • 行列をベクトルに(C言語)

    行列をベクトルに(C言語) m行n列の行列Aがあったとき、それをm×n行1列の行列(ベクトル)Bに するというプログラムを作りたいです。 これは、行列Aの1列目m行分の要素をそのまま行列Bの1行1列目に持っていき、 それを行列Aのn列の数だけ繰り返す、といった要領です(画像参照) つまり MATRIX B; B.m=A.m*A.n; B.n=1; return B; ということだと思うのですが、なかなかうまいくいきません。 また、構造体も使いたいので、 typedef struct { int m; int n; double *mat; } MATRIX; と宣言しました。 画像は説明のため、一応載せておきました。(例として4列の行列になっています) みなさんよろしくお願いします。

  • 行列の和、積、乗算について(C言語)

    まだC言語の勉強を始めて1か月の初心者なのですが、みなさんにお聞きしたいことがあります。 任意の行列に対して和、積、乗算の関数を作り出力するプログラムを 作りたいのですが、試しに和の関数を作ってビルトしてみたら、 31個もエラーが出て、困っています。 ↓参考書を見ながら、自分なりに考えたプログラムです。 #include <stdio.h> typedef struct matrix{ int m; int n; double data[100][100]; } MATRIX; int main(void) { MATRIX a; MATRIX b; a.m=2; a.n=3; a.data[100][100]={{1,2,1},{2,3,3}}; b.m=2; b.n=3; b.data[100][100]={{2,3,1},{1,2,1}}; kekka=add_mat(MATRIX a,MATRIX b); printf("和:%f,kekka.data); //行列和関数 MATRIX add_mat(MATRIX a,MATRIX b){ MATRIX sum; int i,j; sum.m=a.m; sum.n=a.n; sum.data[100][100]={{0,0,0}{0,0,0}}; for(i=0;i<sum.m;i++){ for(j=0;j<sum.n;j++){ sum.data=(a.data)+(b.data); return sum; } } } return 0; } おそらく相当ダメな感じなのでしょうが、エラー文を読んでも なかなか解決できません。 ちなみに、積の関数は mul_mat(MATRIX c,MATRIX a,MATRIX b){ int i,j,k; for(i = 0; i < a.m; i++){ for(j = 0; j < b.n; j++){ for(k = 0; k < a.n; k++){ C[i][j] = C[i][j] + A[i][k] * B[k][j]; } } } という風に考えました。みなさまのお力を借りたいです。 よろしくお願いします

  • 行列の和、積、乗算(C言語)

    まだC言語の勉強を始めて1か月の初心者なのですが、みなさんにお聞きしたいことがあります。 任意の行列に対して和、積、乗算の関数を作り出力するプログラムを 作りたいのですが、試しに和の関数を作ってビルトしてみたら、 31個もエラーが出て、困っています。 ↓参考書を見ながら、自分なりに考えたプログラムです。 #include <stdio.h> typedef struct matrix{ int m; int n; double data[100][100]; } MATRIX; int main(void) { MATRIX a; MATRIX b; a.m=2; a.n=3; a.data[100][100]={{1,2,1},{2,3,3}}; b.m=2; b.n=3; b.data[100][100]={{2,3,1},{1,2,1}}; kekka=add_mat(MATRIX a,MATRIX b); printf("和:%f,kekka.data); //行列和関数 MATRIX add_mat(MATRIX a,MATRIX b){ MATRIX sum; int i,j; sum.m=a.m; sum.n=a.n; sum.data[100][100]={{0,0,0}{0,0,0}}; for(i=0;i<sum.m;i++){ for(j=0;j<sum.n;j++){ sum.data=(a.data)+(b.data); return sum; } } } return 0; } おそらく相当ダメな感じなのでしょうが、エラー文を読んでも なかなか解決できません。 ちなみに、積の関数は mul_mat(MATRIX c,MATRIX a,MATRIX b){ int i,j,k; for(i = 0; i < a.m; i++){ for(j = 0; j < b.n; j++){ for(k = 0; k < a.n; k++){ C[i][j] = C[i][j] + A[i][k] * B[k][j]; } } } という風に考えました。みなさまのお力を借りたいです。 よろしくお願いします。

  • c言語 行列の積に関して

    <問>  4行3列の行列aと3行4列の行列bの積を、4行4列の行列cに格納する関数を作成せよ。  void mat_mul(const int a[4][3], const int b[3][4], int c[4][4]) 入門レベルのスキルしかありません。 上手く行列の積のプログラムが組めません。 行列の積の計算結果が何も出てきません。 どの様にしたら良いかご指導の程、宜しくお願いします。 <プログラム>  void mat_mul(const int a[4][3], const int b[3][4], int c[4][4]) { int i, j, k; for (i = 0; i < 4; k++) { for (j = 0; j < 4; i++) for (k = 0; k < 3; j++) c[i][j] = c[i][j] + (a[i][k] * b[k][j]); } } void mat_print(const int m[4][4]) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) printf("%4d", m[i][j]); putchar('\n'); } } int main(void) { int i, j ,k; int tensu1[4][3]; int tensu2[3][4]; int seki[4][4]; for(i = 0; i < 4; i++) { for (j = 0; j < 3; j++) { scanf("%d", &tensu1[i][j]); } putchar('\n'); } for(i = 0; i < 3; i++) { for(j = 0; j < 4; j++){ scanf("%d", &tensu2[i][j]); } putchar('\n'); } putchar('\n'); mat_mul(tensu1, tensu2, seki); puts("行列の積"); mat_print(seki); return 0; }  

  • 行列をベクトルに

    m行n列の行列Aがあったとき、それをm×n行1列の行列(ベクトル)Bに するというプログラムを作りたいです。 つまり MATRIX B; B.m=A.m*A.n; B.n=1; return B; ということだと思うのですが、なかなかうまいくいきません。 また、構造体も使いたいので、 typedef struct { int m; int n; double *mat; } MATRIX; と宣言しました。 みなさんよろしくお願いします。

  • 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言語のプログラムで行列の積を計算する

    指定された行・列数(それぞれ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言語の行列の積

    現在C言語を勉強中で2列2列の行列の積のコードを書きたいのですが、 いまいちうまくできません。 int main () {  int i,j;  int M1[2][2] = {{1,2},{3,4}};  int M2[2][2] = {{-1,5},{-2,-2}};  int A[2][2];  for (i=0;i<2;i++)  {   for (j=0;j<2;j++)   {    A[i][j]=0;    A[i][j]+=M1[i][j]*M2[i][j];    printf("%d\t",A[i][j]);   }  printf("\n");  } return 0; } 調べたりしてなんとか書いてはみたのですが理解が浅く、 コンパイルできても違う答えが返ってきます。 どこがどう間違っていますか? また、どのようにしたらうまいコードになりますか? 何卒、よろしくお願いします。

  • Visual C++ 2005 行列のプログラムがうまくいきません

    Visual C++ 2005 で行列プログラムを作っているのですが、上手くいきません。初心者ですのでとても下らない間違えの可能性もありますが、ご教授下さい。 /*matrix*/ #include<stdio.h> int main(){ int i, j, m[2][2]; for(i=0; i<3; i++){ for(j=0; j<3; j++){ printf("matrix[%d][%d] ",i+1, j+1); scanf("%d",&m[i][j]); } } printf("matrix\n"); for(i=0; i<3; i++){ for(j=0; j<3; j++){ printf("%d ",m[i][j]); } printf("\n"); } printf("transposed matrix\n"); for(i=0; i<3; i++){ for(j=0; j<3; j++){ printf("%d ",m[j][i]); } printf("\n"); } } とプログラムし、デバックなしで開始すると。 matrix[1][1] 1 matrix[1][2] 2 matrix[1][3] 3 matrix[2][1] 4 matrix[2][2] 5 matrix[2][3] 6 matrix[3][1] 7 matrix[3][2] 8 matrix[3][3] 9 matrix 1 2 4 4 5 7 7 8 9 transposed matrix 1 4 7 2 5 8 4 7 9 続行するには何かキーを押してください . . . となってしまいます。 予定では matrix[1][1] 1 matrix[1][2] 2 matrix[1][3] 3 matrix[2][1] 4 matrix[2][2] 5 matrix[2][3] 6 matrix[3][1] 7 matrix[3][2] 8 matrix[3][3] 9 matrix 1 2 3 4 5 6 7 8 9 transposed matrix 1 4 7 2 5 8 3 6 9 続行するには何かキーを押してください . . . となって欲しいのですが。何処が間違っているんでしょうか。できれば正しいプログラムまで載せていただけると助かります。

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

専門家に質問してみよう