PowerPoint プレゼンテーション

平成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