• ベストアンサー

部分行列の抜き出し(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

専門家に質問してみよう