平成12年度定期試験 解答例 プログラミング方法論 数理情報システム工学科 平成13年2月6日実施 汐月哲夫 2001/2/6 プログラミング方法論 [email protected] 1 問題文 1:下(次のスライド)のプログラムは2×3の行 列と3×2の行列の掛け算を行うプログラムである。 行列の掛け算は関数 mat_mul() で行われる。void mat_mul( );を完成せよ. void mat_mul(double x[2][3], double y[3][2], double z[2][2]){ 2001/2/6 プログラミング方法論 [email protected] 2 問題文(つづき) void mat_mul(double x[2][3], double y[3][2], double z[2][2]){ 解答欄 #include <stdio.h> main プログラム int main( void ) { double a[2][3] = {{1,2,3},{4,5,6}}; double b[3][2]={{1,2},{3,4},{5,6}}; double c[2][2]; mat_mul(a,b,c); <c の内容を出力> return 0; } 2001/2/6 プログラミング方法論 [email protected] 3 問題文(つづき2) 2001/2/6 プログラミング方法論 [email protected] 4 解答例 void mat_mul(double a[2][3],double b[3][2],double c[2][2]) { int i,j,k; double x; for(i=0;i<2;i++) { for(j=0;j<2;j++) { x = 0.0; for(k=0; k<3; k++ ) { x += a[i][k]*b[k][j]; } c[i][j] = x; } } } 2001/2/6 プログラミング方法論 [email protected] 5 行列の掛け算(1) (3×2行列) (2×3行列) (2×2行列) = 1行成分 × 1列成分 1行1列成分 i 行成分 × j 列成分 i 行j 列成分 ai1b1 j ai 2b2 j aimbmj 2001/2/6 プログラミング方法論 [email protected] cij 6 行列データの表現 C言語の2次元配列の利用 C言語の記述 宣言部: double a[2][3]; 数学の記述 a[0][0] a[0][1] a[0][2] a11 a12 a13 a[1][0] a[1][1] a[1][2] 実行文 a[0][0]=1; x = a[0][2]*a[1][0]; a21 a22 a23 注意: a[2][1], a[0][3] などは添え字エラー 2001/2/6 プログラミング方法論 [email protected] 7 行列の掛け算(2) c[0][0]=a[0][0]*b[0][0]+a[0][1]*b[1][0]+a[0][2]*b[2][0]; c[0][1]=a[0][0]*b[0][1]+a[0][1]*b[1][1]+a[0][2]*b[2][1]; c[1][0]=a[1][0]*b[0][0]+a[1][1]*b[1][0]+a[1][2]*b[2][0]; c[1][1]=a[1][0]*b[0][1]+a[1][1]*b[1][1]+a[1][2]*b[2][1]; 内側の添え字を for-loop で処理すると c[0][0]= c[0][1]= c[1][0]= c[1][1]= 0.0; for(k=0; k<3; k++) { c[0][0] += a[0][k]*b[k][0]; c[0][1] += a[0][k]*b[k][1]; c[1][0] += a[1][k]*b[k][0]; c[1][1] += a[1][k]*b[k][1]; } 2001/2/6 行と列の添え字を プログラミング方法論 [email protected] for-loop で処理すると 8 行列の掛け算(3) for(i=0; i<2; i++) { for(j=0; j<2; j++) { c[i][j] = 0.0; c[i][j] の呼び出し回数を減らすと for(k=0; k<3; k++) { c[i][j] += a[j][k]*b[k][j]; } } for(i=0; i<2; i++) { } for(j=0; j<2; j++) { x = 0.0; for(k=0; k<3; k++) { 実際のコーディングにおいては x += a[j][k]*b[k][j]; 宣言部での } int i,j,k; c[i][j] = x; double x } を忘れないこと。 } 2001/2/6 プログラミング方法論 [email protected] 9 行列データの出力(プログラム例) printf("A=\n"); // print a for(i=0;i<2;i++) { for(j=0;j<3;j++) { printf("%15.8lf ",a[i][j]); } printf("\n"); } A= 1.00000000 4.00000000 2001/2/6 画面出力例 2.00000000 5.00000000 プログラミング方法論 [email protected] 3.00000000 6.00000000 10 関数と配列 void mat_mul(double a[2][3],double b[3][2],double c[2][2]) { int i,j,k; double x; a[0][0] for(i=0;i<2;i++) { 配列の先頭アドレスと for(j=0;j<2;j++) { 添え字計算に必要な a[0][1] x = 0.0; 情報が渡される for(k=0; k<3; k++ ){ a[0][2] x += a[i][k]*b[k][j]; } c[i][j] = x; a[1][0] } メモリ上にはこのように } a[1][1] } 一列にならんでいる a[1][2] 2001/2/6 プログラミング方法論 [email protected] 11 配列の添え字とポインタ演算 2次元配列 としての表記 1次元配列 としての表記 数学表記と1次元配列 としての表記の対応 a[0][0] *(a+0) a[0] *(a+0) a11 *(a+(1-1)*3+(1-1)) a[0][1] *(a+1) a[1] *(a+1) a12 *(a+(1-1)*3+(2-1)) a[0][2] *(a+2) a[2] *(a+2) a13 *(a+(1-1)*3+(3-1)) a[1][0] *(a+3*1+0) a[3] *(a+3) a21 *(a+(2-1)*3+(1-1)) a[1][1] *(a+3*1+1) a[4] *(a+4) a22 *(a+(2-1)*3+(2-1)) a[1][2] *(a+3*1+2) a[5] *(a+5) a23 *(a+(2-1)*3+(3-1)) 2001/2/6 プログラミング方法論 [email protected] 12 問題文 2:1の mat_mul() では行列のサイズが固定され てしまうので、以下のような構造体を定義して任意 のサイズの行列の掛け算ができる mat_mul2() を作 成せよ。 struct matrix { int row, col; double * data; }; 2001/2/6 row col {{1,2,3},{4,5,6}} data プログラミング方法論 [email protected] 13 問題文(つづき) void mat_mul2(struct matrix * x, struct matrix * y, struct matrix * z) { 解答欄 int main( void ) { main プログラム { struct matrix a,b,c; a.row = 2; a.col=3; a.data = (double *)malloc(sizeof(double)*a.row*a.col); < a.data にデータをセットする > < 行列 b についても同様 > c.data = (double *)malloc(sizeof(double)*a.row*b.col); mat_mul2(&a, &b, &c); } < c の内容を出力する 2001/2/6 > プログラミング方法論 [email protected] 14 main プログラムの解説 struct matrix a,b,c; 構造体を定義する。つまり、 構造体の領域確保、型定義、名前定義、を行う(初期化なし)。 a.row = 2; a.col=3; 行(row)と列(column)の値をセットする a.data = (double *)malloc(sizeof(double)*a.row*a.col); データを格納する領域を確保する。 mat_mul2(&a, &b, &c); mat_mul2() には構造体の先頭アドレスを渡す(参照渡し) 2001/2/6 プログラミング方法論 [email protected] 15 行列データの初期化 プログラムの先頭で次のような定義をしておくと #define A(i,j) (*(a.data + (i-1)*a.col + (j-1))) プログラム中では以下のような記述が可能となる a.row = 2; a.col=3; A(1,1) = 1; A(1,2) = 2; A(1,3) = 3; A(2,1) = 4; A(2,2) = 5; A(2,3) = 6; 2001/2/6 プログラミング方法論 [email protected] 16 関数定義部での行列データの扱い 関数定義部では構造体のポインタを使用しているので、 プログラムの先頭で次のような定義をしておくと #define X(i,j) (*(x->data + (i-1)*x->col + (j-1))) プログラム中では以下のような記述が可能となる z->row = x->row; z->col = y->col; for(k=1; k<=x->col; k++ ) { temp += X(i,k)*Y(k,j); } Z(i,j) = temp; 2001/2/6 プログラミング方法論 [email protected] 17 問い2の解答例 main プログラムの先頭に以下を追加する #define #define #define #define #define #define X(i,j) Y(i,j) Z(i,j) A(i,j) B(i,j) C(i,j) (*(x->data + (i-1)*x->col + (j-1))) (*(y->data + (i-1)*y->col + (j-1))) (*(z->data + (i-1)*z->col + (j-1))) (*(a.data + (i-1)*a.col + (j-1))) (*(b.data + (i-1)*b.col + (j-1))) (*(c.data + (i-1)*c.col + (j-1))) つづく 2001/2/6 プログラミング方法論 [email protected] 18 問い2の解答例(つづき) void mat_mul2(struct matrix *x, struct matrix *y, struct matrix *z ) { int i,j,k; double temp; z->row = x->row; z->col = y->col; for(i=1;i<=x->row;i++) { for(j=1;j<=y->col;j++) { temp = 0.0; for(k=1; k<=x->col; k++ ) { temp += X(i,k)*Y(k,j); } Z(i,j) = temp; } } }2001/2/6 プログラミング方法論 [email protected] 19 問い1解答例(完全版) printf("A=\n"); // print a for(i=0;i<2;i++) { for(j=0;j<3;j++) { printf("%15.8lf ",a[i][j]); } printf("\n"); } printf("B=\n"); // print b for(i=0;i<3;i++) { for(j=0;j<2;j++) { printf("%15.8lf ",b[i][j]); } printf("\n"); } mat_mul(a,b,c); // a*b -> c #include <stdio.h> void mat_mul(double a[2][3],double b[3][2], double c[2][2]) { int i,j,k; double x; for(i=0;i<2;i++) { for(j=0;j<2;j++) { x = 0.0; for(k=0; k<3; k++ ) { x += a[i][k]*b[k][j]; } c[i][j] = x; } } } int main( void ) { double a[2][3] = {{1,2,3},{4,5,6}}; double b[3][2] = {{1,2},{3,4},{5,6}}; double c[2][2]; int i,j; 2001/2/6 } printf("C=\n"); // print c for(i=0;i<2;i++) { for(j=0;j<2;j++) { printf("%15.8lf ",c[i][j]); } printf("\n"); } return 0; プログラミング方法論 [email protected] 20 問い2解答例(完全版) (1/4) #include <stdio.h> #define #define #define #define #define #define X(i,j) Y(i,j) Z(i,j) A(i,j) B(i,j) C(i,j) (*(x->data + (i-1)*x->col + (j-1))) (*(y->data + (i-1)*y->col + (j-1))) (*(z->data + (i-1)*z->col + (j-1))) (*(a.data + (i-1)*a.col + (j-1))) (*(b.data + (i-1)*b.col + (j-1))) (*(c.data + (i-1)*c.col + (j-1))) void mat_mul2(struct matrix *x, struct matrix *y, struct matrix *z ) { int i,j,k; double temp; struct matrix { int row, col; double * data; }; } 2001/2/6 (2/4) z->row = x->row; z->col = y->col; for(i=1;i<=x->row;i++) { for(j=1;j<=y->col;j++) { temp = 0.0; for(k=1; k<=x->col; k++ ) { temp += X(i,k)*Y(k,j); } Z(i,j) = temp; } } プログラミング方法論 [email protected] 21 問い2解答例(完全版) int main( void ) { struct matrix a, b, c; int i,j; (3/4) printf("A=\n"); // print a for(i=1;i<=2;i++) { for(j=1;j<=3;j++) { printf("%15.8lf ", A(i,j)); } printf("\n"); } printf("B=\n"); // print b for(i=1;i<=3;i++) { for(j=1;j<=2;j++) { printf("%15.8lf ", B(i,j)); } printf("\n"); } mat_mul2(&a, &b, &c); // a*b -> c // set values of a and b a.row = 2; a.col = 3; a.data = (double *)malloc(sizeof(double)*a.row*a.col); A(1,1) = 1; A(1,2) = 2; A(1,3) = 3; A(2,1) = 4; A(2,2) = 5; A(2,3) = 6; b.row = 3; b.col = 2; b.data = (double printf("C=\n"); // print c *)malloc(sizeof(double)*b.row*b.col); for(i=1;i<=2;i++) { B(1,1) = 1; for(j=1;j<=2;j++) { B(1,2) = 2; printf("%15.8lf ", C(i,j)); B(2,1) = 3; } B(2,2) = 4; printf("\n"); B(3,1) = 5; } B(3,2) = 6; return 0; c.data = (double } *)malloc(sizeof(double)*a.row*b.col); 2001/2/6 プログラミング方法論 [email protected] (4/4) 22
© Copyright 2024 ExpyDoc