Download : sample-001.c
/* * 2017/10/27 sample-001.c */ /* * 複素数型の定義と計算 * * 利用方法 * コンパイル * cc -c sample-001.c * リンク * cc -o sample-001.exe sample-001.c * 実行 * ./sample-001.exe */ #include <stdio.h> /* * 複素数型を表す Complex の定義 * * 複素数 z は、二つの実数 x, y を用いて * z = x + yi ( i は虚数単位 ) * と表現できる。 * C 言語では実数を表すのに浮動小数点数型の double を用いる * 型名 ( Complex ) を大文字で始めるのは「ソフトウェア概論ルール」 */ typedef struct { double real; /* 実部 */ double imaginary; /* 虚部 */ } Complex; /* 複素数型 */ /* * Complex make_Complex ( double x, double y ) * Complex 型の数を作り、返す * x, y -> z = x + yi */ Complex make_Complex ( double x, double y ) { Complex newComplex; /* 新しく作られる複素数 */ newComplex.real = x; /* 新しく作られた複素数の実部は x */ newComplex.imaginary = y; /* 新しく作られた複素数の実部は y */ return newComplex; /* 新しく作られる複素数を値として返す */ } /* * double real_part ( Complex z ) * Complex 型の数の実部を返す * z = x + yi -> x */ double real_part ( Complex z ) { return z.real; } /* * double imaginary_part ( Complex z ) * Complex 型の数の実部を返す * z = x + yi -> x */ double imaginary_part ( Complex z ) { return z.imaginary; } /* * print_Complex ( Complex z ) * Complex 型の数の出力 * z = x + y i だが、y < 0 の時は z = x - (-y) i となるように工夫 */ void print_Complex ( Complex z ) { if ( z.imaginary > 0 ) { printf ( "%f + %f i", z.real, z.imaginary ); } else { printf ( "%f - %f i", z.real, - z.imaginary ); } } /* * Complex add_Complex ( Complex z1, Complex z2 ) * Complex 型の数の足し算 * z1 = x1 + y1 i * z2 = x2 + y2 i * -> z1 + z2 = ( x1 + x2 ) + ( y1 + y2 ) i */ Complex add_Complex ( Complex z1, Complex z2 ) { Complex result; /* 複素数の和の実部は、実部の和 */ result.real = z1.real + z2.real; /* 複素数の和の虚部は、虚部の和 */ result.imaginary = z1.imaginary + z2.imaginary; return result; } /* * main */ int main( int argc, char *argv[] ) { Complex z1 = make_Complex ( 2.0, 3.0 ); /* z1 = 2 + 3i */ Complex z2 = make_Complex ( -1.0, 5.0 ); /* z2 = -1 + 5i */ Complex z3; printf ( " z1 ( = " ); print_Complex ( z1 ); printf ( " ) と、" ); printf ( " z2 ( = " ); print_Complex ( z2 ); printf ( " ) の和は 、\n" ); z3 = add_Complex ( z1, z2 ); /* z3 <- z1 + z2 */ print_Complex ( z3 ); printf ( " です。\n" ); return 0; }
$ ./sample-001.exe z1 ( = 2.000000 + 3.000000 i ) と、 z2 ( = -1.000000 + 5.000000 i ) の和は 、 1.000000 + 8.000000 i です。 $
Download : sample-002.c
/* * 2017/10/27 sample-002.c */ /* * 二次元行列型の定義と計算 * * 利用方法 * コンパイル * cc -c sample-002.c * リンク * cc -o sample-002.exe sample-002.c * 実行 * ./sample-002.exe */ #include <stdio.h> /* * */ #define DIMENSION 2 /* 二次元 */ /* * 行列 A は、2 x 2 = 4 の要素をもっている * * A = ( 1 2 ) = ( a[0][0] a[0][1] ) * 3 4 a[1][0] a[1][1] * */ typedef struct { double a[DIMENSION][DIMENSION]; /* 二次元の行列の要素は 2 x 2 */ } Matrix2D; /* Matrix2D 型の宣言 */ /* * Matrix2D make_Matrix2D ( double a, double b, double c, double d ) * 「行列」を作成する * * A = ( a b ) = ( a[0][0], a[0][1] ) * ( c d ) ( a[1][0], a[1][1] ) */ Matrix2D make_Matrix2D ( double a, double b, double c, double d ) { Matrix2D newMatrix2D; /* 新しい行列 */ newMatrix2D.a[0][0] = a; newMatrix2D.a[0][1] = b; newMatrix2D.a[1][0] = c; newMatrix2D.a[1][1] = d; return newMatrix2D; } /* * void print_Matrix2D ( Matrix2D ary ); * 「行列」を表示する (表示の都合上、常に独立した行に出力する) * Matrix2D ary; 二次元行列 */ void print_Matrix2D ( Matrix2D ary ) { int r; /* 行 ( row ) */ int c; /* 列 ( colomun ) */ for ( r = 0; r < DIMENSION; r++ ) { printf ( "(" ); for ( c = 0; c < DIMENSION; c++ ) { printf ( " %10.5f", ary.a[r][c] ); /* * [注意] %10.5f は %f と同じく浮動小数点数を出力するが * 「全体の桁数は 10 桁、小数点数以下は 5 桁にする」 * という「表示上の指定」も加わっている * 詳しくは google で「printf 書式」で検索 */ } printf ( " )\n" ); } } /* * Matrix2D add_Matrix2D ( Matrix2D a1, Matrix2D a2 ); * 「行列」の和 * * ( a b ) + ( e f ) = ( a + e b + f ) * ( c d ) ( g h ) ( c + g g + h ) */ Matrix2D add_Matrix2D ( Matrix2D a1, Matrix2D a2 ) { Matrix2D result; /* 計算結果 */ int r; /* 行 ( row ) */ int c; /* 列 ( colomun ) */ for ( r = 0; r < DIMENSION; r++ ) { for ( c = 0; c < DIMENSION; c++ ) { result.a[r][c] = a1.a[r][c] + a2.a[r][c]; } } return result; } /* * main */ int main( int argc, char *argv[] ) { /* a1 = ( 1 2 ) ( 3 -1 ) a2 = ( -3 1 ) ( 1 -2 ) */ Matrix2D a1 = make_Matrix2D ( 1.0, 2.0, 3.0, -1.0 ); Matrix2D a2 = make_Matrix2D ( -3.0, 1.0, 1.0, -2.0 ); /* 行列 a1 と行列 a2 の和を計算して出力する */ print_Matrix2D ( a1 ); printf ( " と、 \n" ); print_Matrix2D ( a2 ); printf ( " との、和は \n" ); print_Matrix2D ( a ); printf ( " です。\n" ); return 0; }
$ ./sample-002.exe z1 ( = 2.000000 + 3.000000 i ) と、 z2 ( = -1.000000 + 5.000000 i ) の和は 、 1.000000 + 8.000000 i です。 $
/* * 課題 20171020-02 * * 20171020 20171020-02-QQQQ.c * * 直交座標系を利用した平面上の点に対して * 構造体を利用し、平行移動を行う関数を作成する * 例: * 点(1,2) : x 軸方向に +10, y 軸方向に -20 * => 点(11,-18) */ #include <stdio.h> /* * 最初に、直交座標で「点」を表現する型 (Orthogonal) を作ってしまう * Orthogonal 型は、二つの要素 ( x, y ) からなり、それらの型は double 型 * * Orthogonal <----> double * double * \in \in * p <----> ( p.x, p.y ) * * 残念ながら、C 言語の型定義機能で出来るのは「形(式)」の定義だけで * 「意味」の定義はできない * 「形」に「意味」をつけるのは、「それを扱うプログラム(関数)」の役目 * * コーディングルール: * 現実の世界 コンピュータの世界 * * 平面上の点 P : ( x, y ) Orthogonal 型の pt : ( pt.x, pt.y ) * P の x 座標 : 3 pt.x = 3.0 * P の y 座標 : -2 pt.y = -2.0 * * [注意] * Orthogonal 型の pt を「現実の点 P」に対応させ、 * pt.x を点数 P の直交座標系における x 座標 * pt.y を点数 P の直交座標系における y 座標 * とする対応は、「决め(る)事」であり、 * 「必然的に『決る物』」では *ない* * <反例 1> * x と y の名前は恣意的な物なので、逆にしても問題はない * つまり、 * pt.x を点数 P の直交座標系における y 座標 * pt.y を点数 P の直交座標系における x 座標 * と、対応させても、「プログラム上」はなんら問題ない * (正く動くように作る事ができる) * <反例 2> * x と y の値の対応も恣意的な物なので、変更してもよい * つまり、 * pt.x を点数 P の偏角 * pt.y を点数 P の動径 * 対応させても、「プログラム上」はなんら問題ない * (正く動くように作る事ができる) */ typedef struct { double x; /* 直交座標の x 座標を表すタグ名(x)とその型(double)の宣言 */ double y; /* 直交座標の y 座標を表すタグ名(y)とその型(double)の宣言 */ } Orthogonal; /* Orthogonal 型の宣言 */ /* * void print_point ( Orthogonal pt ); * 「点」を表示する * Orthogonal pt; 直交座標系の座標で表現された「点」 */ void print_point ( Orthogonal pt ) { /* * 構造体の要素は、タグ名を利用して参照できる */ printf ( "( %f, %f )", pt.x, pt.y ); } /* * Orthogonal shift_point ( Orthogonal pt, double delta_x, double delta_y ) * 点を平行移動する * Orthogonal pt; 直交座標系の座標で表現された「点」 * double delta_x; x 軸方向の変異 (Δx) * double delta_y; y 軸方向の変異 (Δy) * 値 平行移動した結果 */ Orthogonal shift_point ( Orthogonal pt, double delta_x, double delta_y ) { Orthogonal result; /* 返す値を入れる変数 */ /* result には、 pt を、x 軸方向に delta_x だけ y 軸方向に delta_y だけ並行移動した点が入ってほしい */ /* x 軸方向に delta_x だけ平行移動した result.x を得るには、 pt の x 座標に delta_x を加えればよい */ result.x = pt.x + delta_x; /* y 軸方向に delta_y だけ平行移動した result.x を得るには、 pt の y 座標に delta_y を加えればよい */ /* ** この部分を完成させなさい(上と同様なので各自考える) */ return result; /* 構造体の値が返せる */ } /* * main */ int main( int argc, char *argv[] ) { Orthogonal p1; Orthogonal p2; double dx = 10.0; double dy = -100.0; p1.x = 1.0; /* p1 = ( 1.0, 2.0 ) */ p1.y = 2.0; /* 平行移動 */ printf ( "点 " ); /* 構造体は引数で、そのまま渡せる */ print_point ( p1 ); printf ( " を x 軸方向に %f, y 軸方向に %f 移動した点は ", dx, dy ); /* 構造体は、値としても取り出せるし、普通に代入もできる */ p2 = shift_point( p1, dx, dy ); print_point ( p2 ); printf ( " となります。\n" ); return 0; }
/* * 課題 20171020-03 * * 20171020 20171020-03-QQQQ.c * * 3 次元ベクトルの差の計算 * */ #include <stdio.h> /* * 3 次元ベクトル */ typedef struct { /* 3 次元ベクトル */ double x; /* x 要素 */ double y; /* y 要素 */ double z; /* z 要素 */ } Vector3D; /* 新しい型 : Vector3D */ /* 三次元の点の表現と同じでは ? -> Yes ( 点と位置ベクトルは、一対一 自由ベクトルは、一ベクトルの原点を平行移動したもの ) 現実は、同じもの しかし、「データ型」としては「区別」する必要がある */ /* * void print_Vector3D ( Vector3D v ) * ベクトルの内容を書き出す * Vector3D v; 書き出すベクトル */ void print_Vector3D ( Vector3D v ) { printf ( " %f\n", v.x ); /* v の x 要素の出力 */ printf ( "( %f )\n", v.y ); /* v の y 要素の出力 */ printf ( " %f\n", v.z ); /* v の z 要素の出力 */ /* TeX で表現するならば、 printf ( "\\left(\\begin{array}{c} %f \\\\ %f \\\ %f \\end{array}\\right)\n", v.x, v.y, v.z ); などととすればよい。 */ } /* * Vector3D sub_Vector3D ( Vector3D dst, Vector3D src ) * 二つのベクトルの差を計算する * Vector3D dst; 引かれるベクトル * Vector3D src; 引くベクトル * 帰り値 二つのベクトルの差となるベクトル */ Vector3D sub_Vector3D ( Vector3D dst, Vector3D src ) { Vector3D result; /* 計算結果(差)を收める変数 */ /* result = dst - src; ベクトルとして v3 = v1 - v2 <=> x3 x1 x2 x1 - x2 ( y3 ) = ( y1 ) - ( y2 ) = ( y1 - y2 ) z3 z1 z2 z1 - z2 <=> x3 = x1 - x2 y3 = y1 - y2 z3 = z1 - z2 [注意] 数学の知識(定義)を利用している 自分で、手でやるときと同じ結果 */ result.x = dst.x - src.x; /* x 成分の計算 */ result.y = dst.y - src.y; /* y 成分の計算 */ /* ** この部分を完成させなさい(上と同様:zとについてやる) */ /* z 成分の計算 */ return result; /* 計算した結果を値として返す */ } /* * main */ int main( int argc, char *argv[] ) { Vector3D dst; Vector3D src; dst.x = 1.2; /* 1.2 */ dst.y = 2.3; /* dst = ( 2.3 ) */ dst.z = 3.4; /* 3.4 */ src.x = -9.8; /* -9.8 */ src.y = 8.7; /* dst = ( 8.7 ) */ src.z = 0.0; /* 0.0 */ print_Vector3D ( dst ); /* dst の出力 */ printf ( "と\n" ); print_Vector3D ( src ); /* src の出力 */ printf ( "の差は\n" ); print_Vector3D ( sub_Vector3D ( dst, src ) ); printf ( "となります。\n" ); return 0; }
/* * 課題 20171027-01 * * 20171027 20171027-01-QQQQ.c * * 複素数型の四則 * 構造体の使い方 * class (空間)の概念 * データ型 + そのデータ型を処理する関数 */ #include <stdio.h> /* * 複素数型の定義と計算 * * 利用方法 * コンパイル * cc -Ic:\usr\c\include -o BASENAME.exe 20171027-01-QQQQ.c * 実行 * BASENAME */ #include <stdio.h> /* * 複素数型を表す Complex の定義 * * 複素数 z は、二つの実数 x, y を用いて * z = x + yi ( i は虚数単位 ) * と表現できる。 * C 言語では実数を表すのに浮動小数点数型の double を用いる * 型名 ( Complex ) を大文字で始めるのは「ソフトウェア概論ルール」 */ typedef struct { double real; /* 実部 */ double imaginary; /* 虚部 */ } Complex; /* 複素数型 */ /* * Complex make_Complex ( double x, double y ) * Complex 型の数を作り、返す * x, y -> z = x + yi */ Complex make_Complex ( double x, double y ) { Complex newComplex; /* 新しく作られる複素数 */ newComplex.real = x; /* 新しく作られた複素数の実部は x */ newComplex.imaginary = y; /* 新しく作られた複素数の実部は y */ return newComplex; /* 新しく作られる複素数を値として返す */ } /* * double real_part ( Complex z ) * Complex 型の数の実部を返す * z = x + yi -> x */ double real_part ( Complex z ) { return z.real; } /* * double imaginary_part ( Complex z ) * Complex 型の数の実部を返す * z = x + yi -> x */ double imaginary_part ( Complex z ) { return z.imaginary; } /* * print_Complex ( Complex z ) * Complex 型の数の出力 * z = x + y i だが、y < 0 の時は z = x - (-y) i となるように工夫 */ void print_Complex ( Complex z ) { if ( z.imaginary > 0.0 ) { printf ( "%f + %f i", z.real, z.imaginary ); } else { printf ( "%f - %f i", z.real, - z.imaginary ); } } /* * Complex add_Complex ( Complex z1, Complex z2 ) * Complex 型の数の足し算 * z1 = x1 + y1 i * z2 = x2 + y2 i * -> z1 + z2 = ( x1 + x2 ) + ( y1 + y2 ) i * 数学の定義に基づく */ Complex add_Complex ( Complex z1, Complex z2 ) { Complex result; /* 複素数の和の実部は、実部の和 */ result.real = z1.real + z2.real; /* 複素数の和の虚部は、虚部の和 */ result.imaginary = z1.imaginary + z2.imaginary; return result; } /* * Complex sub_Complex ( Complex z1, Complex z2 ) * Complex 型の数の引き算 * z1 = x1 + y1 i * z2 = x2 + y2 i * -> z1 - z2 = ( x1 - x2 ) + ( y1 - y2 ) i */ Complex sub_Complex ( Complex z1, Complex z2 ) { Complex result; /* 複素数の差の実部は、実部の差 */ result.real = z1.real - z2.real; /* 複素数の差の虚部は、虚部の差 */ result.imaginary = z1.imaginary - z2.imaginary; /* + の場合と同様 */ return result; } /* * Complex mul_Complex ( Complex z1, Complex z2 ) * Complex 型の数のかけ算 * z1 = x1 + y1 i * z2 = x2 + y2 i * の時 * z1 * z2 = (x1 + y1 i)*(x2 + y2 i) = x1 *(x2 + y2 i) + y1i *( x2 + y2 i) = x1 * x2 + x1 * y2 i) + y1 i * x2 + y1 i *y2 i = x1 * x2 + x1 * y2 i) + y1 i * x2 - y1*y2 * = (x1 * x2 - y1 * y2) + (x1 * y2 + x2 * y1) i * 数学的な定義に基づいて考えればよい */ Complex mul_Complex ( Complex z1, Complex z2 ) { Complex result; result.real = z1.real * z2.real - z1.imaginary * z2.imaginary; result.imaginary = z1.real * z2.imaginary + z1.imaginary * z2.real; return result; } /* * Complex div_Complex ( Complex z1, Complex z2 ) * Complex 型の数の割り算 * z1 = x1 + y1 i * z2 = x2 + y2 i * の時 * z1 / z2 = ( x1 + y1 i ) / ( x2 + y2 i ) * = ( x1 + y1 i )( x2 - y2 i ) / ( x2 + y2 i )( x2 - y2 i ) * = ( x1 * x2 + y1 * y2) / ( x2^2 + y2^2 ) * + ( (- x1 * y2 + x2 * y1) / ( x2^2 + y2^2 ) ) i */ Complex div_Complex ( Complex z1, Complex z2 ) { Complex result; double denominator = z2.real * z2.real + z2.imaginary *z2.imaginary; /* 実部、虚部の割る数 |z2|^2 を予め計算しておく */ /* ** この部分を完成させなさい */ result.imaginary = ( - z1.real * z2.imaginary + z1.imaginary * z2.real ) / denominator; return result; } /* * print_result 演算結果を出力する */ void print_result ( Complex z1, Complex z2, char *operator, Complex z ) { print_Complex ( z1 ); printf ( " と、 " ); print_Complex ( z2 ); printf ( " との、%s は ", operator ); print_Complex ( z ); printf ( " です。\n" ); } /* * main */ int main( int argc, char *argv[] ) { Complex z1 = make_Complex ( 20.0, -15.0 ); /* z1 = 20 - 15i */ Complex z2 = make_Complex ( 1.0, 2.0 ); /* z2 = 1 + 2i */ /* 和の出力 */ print_result ( z1, z2, "和", add_Complex ( z1, z2 ) ); /* 差の出力 */ print_result ( z1, z2, "差", sub_Complex ( z1, z2 ) ); /* 積の出力 */ /* ** この部分を完成させなさい */ /* 商の出力 */ print_result ( z1, z2, "商", div_Complex ( z1, z2 ) ); return 0; }
/* * 課題 20171027-02 * * 20171027 20171027-02-QQQQ.c * * 二次元行列型の定義と計算 * 数学の様々な概念(空間)に対応した「データ型」を作る事ができる * 自分で考えた新しい空間も扱える * -> 多く場合は、すでにライブラリ化されている * * 構造体と配列のハイブリット */ #include <stdio.h> /* * */ #define DIMENSION 2 /* 二次元 */ /* * 行列 A は、2 x 2 = 4 の要素をもっている * * A = ( 1 2 ) = ( a[0][0] a[0][1] ) * 3 4 a[1][0] a[1][1] * */ typedef struct { double a[DIMENSION][DIMENSION]; /* 二次元の行列の要素は 2 x 2 */ /* 配列の配列(二次元配列[行列]だと思ってよい..) double a[10] --> double a[0], a[1], .., a[9] double a[10][10] -> double a[10][0], a[10][1], .. a[0][0], a[9][0] a[0] <-> a[0][0] ... a[0][9] .. a[9] <-> a[9][0] ... a[9][9] !! 当然の事ながら、配列の配列の配列の... とできる !! 添え字はいくつでもつけられる。 */ } Matrix2D; /* Matrix2D 型の宣言 */ /* なぜ、構造体にしなければならないかというと 構造体にしないと、関数の値として扱えないから */ /* * Matrix2D make_Matrix2D ( double a, double b, double c, double d ) * 「行列」を作成する * * A = ( a b ) = ( a[0][0], a[0][1] ) * ( c d ) ( a[1][0], a[1][1] ) */ Matrix2D make_Matrix2D ( double a, double b, double c, double d ) { Matrix2D newMatrix2D; /* 新しい行列 */ newMatrix2D.a[0][0] = a; newMatrix2D.a[0][1] = b; newMatrix2D.a[1][0] = c; newMatrix2D.a[1][1] = d; return newMatrix2D; } /* * void print_Matrix2D ( Matrix2D ary ); * 「行列」を表示する (表示の都合上、常に独立した行に出力する) * Matrix2D ary; 二次元行列 */ void print_Matrix2D ( Matrix2D ary ) { int r; /* 行 ( row ) */ int c; /* 列 ( colomun ) */ /* 行列の要素が配列なので、for で行う */ /* 配列の配列なので、2 重ループになる */ for ( r = 0; r < DIMENSION; r++ ) { printf ( "(" ); for ( c = 0; c < DIMENSION; c++ ) { printf ( " %10.5f", ary.a[r][c] ); /*^^^^ : 表示の追加書式 */ /* * [注意] %10.5f は %f と同じく浮動小数点数を出力するが * 「全体の桁数は 10 桁、小数点数以下は 5 桁にする」 * という「表示上の指定」も加わっている * 詳しくは google で「printf 書式」で検索 */ } printf ( " )\n" ); } } /* * Matrix2D add_Matrix2D ( Matrix2D a1, Matrix2D a2 ); * 「行列」の和 * * ( a b ) + ( e f ) = ( a + e b + f ) * ( c d ) ( g h ) ( c + g g + h ) */ Matrix2D add_Matrix2D ( Matrix2D a1, Matrix2D a2 ) { Matrix2D result; /* 計算結果 */ int r; /* 行 ( row ) */ int c; /* 列 ( colomun ) */ for ( r = 0; r < DIMENSION; r++ ) { for ( c = 0; c < DIMENSION; c++ ) { result.a[r][c] = a1.a[r][c] + a2.a[r][c]; } } return result; } /* * Matrix2D sub_Matrix2D ( Matrix2D a1, Matrix2D a2 ); * 「行列」の差 * * ( a b ) - ( e f ) = ( a - e b - f ) * ( c d ) ( g h ) ( c - g g - h ) */ Matrix2D sub_Matrix2D ( Matrix2D a1, Matrix2D a2 ) { Matrix2D result; /* 計算結果 */ int r; /* 行 ( row ) */ int c; /* 列 ( colomun ) */ for ( r = 0; r < DIMENSION; r++ ) { for ( c = 0; c < DIMENSION; c++ ) { result.a[r][c] = a1.a[r][c] - a2.a[r][c]; } } return result; } /* * Matrix2D mul_Matrix2D ( Matrix2D a1, Matrix2D a2 ); * 「行列」の積 * * ( a b ) ( e f ) = ( a * e + b * g a * f + b * h ) * ( c d ) ( g h ) ( c * e + d * g c * f + d * h ) * * c:2 * r:1-> ( a11 a12 ) ( b11 b12 ) = ( - a11*b12 + a12*b22 ) * ( a21 a22 ) ( b21 b22 ) ( - - ) * = ( - ar1*b1c + ar2*b2c ) * 2 * = ( - Σ ari*bic ) * i=1 */ Matrix2D mul_Matrix2D ( Matrix2D a1, Matrix2D a2 ) { Matrix2D result; /* 計算結果 */ int r; /* 行 ( row ) */ int c; /* 列 ( colomun ) */ int i; for ( r = 0; r < DIMENSION; r++ ) { for ( c = 0; c < DIMENSION; c++ ) { double products = 0.0; /* a1 の r 行と a2 の c 列の内積の結果 */ /* a1 の r 行と a2 の c 列の内積を計算する */ for ( i = 0; i < DIMENSION; i++ ) { products = products + a1.a[r][i] * a2[i][c]; } result.a[r][c] = products; } } return result; } /* * print_result 演算結果を出力する */ void print_result ( Matrix2D a1, Matrix2D a2, char *operator, Matrix2D a ) { printf ( "%s の計算\n", operator ); print_Matrix2D ( a1 ); printf ( " と、 \n" ); print_Matrix2D ( a2 ); printf ( " との、%s は \n", operator ); print_Matrix2D ( a ); printf ( " です。\n\n" ); } /* * main */ int main( int argc, char *argv[] ) { /* a1 = ( 1 2 ) ( 3 -1 ) a2 = ( -3 1 ) ( 1 -2 ) */ Matrix2D a1 = make_Matrix2D ( 1.0, 2.0, 3.0, -1.0 ); Matrix2D a2 = make_Matrix2D ( -3.0, 1.0, 1.0, -2.0 ); /* 和の出力 */ print_result ( a1, a2, "和", add_Matrix2D ( a1, a2 ) ); /* 差の出力 */ /* ** この部分を完成させなさい */ /* 積の出力 */ /* ** この部分を完成させなさい */ return 0; }
/* * 課題 20171027-03 * * 20171027 20171027-03-QQQQ.c * * 整数型の配列を作り、それに 5 個のデータを入力し * その値を 5 倍にしたものと 2 分の 1 にした値を * それぞれ、画面に出力するプログラムを作りなさい * * 5 つのデータを処理したい * 1) 「入力して、処理して、出力する」作業を 5 回する * 従来の考え方で、配列が不要 * -> 一度に一つのデータしか扱えない * 2) 「5 つまとめて、入力し、5つまとめて処理、5 つまとめて出力 * 複数(5つ)のデータを一つに「まとめる」考え方 * 「まとめる」ために「配列」を利用している * => もし、複数のデータを同時に扱い場合 * この方法をとらざるを得ない * この課題では、その必要性はないが.. * * [ポイント] * 配列(の要素)の処理には、 * for 構文の制御変数を添え字に利用する事により、 * ループで簡単に実現できる */ #include <stdio.h> /* * */ #define DATA_SIZE 5 /* データのサイズ (個数) */ /* * */ int main(int argc, char *argv[]) { int array[DATA_SIZE]; /* サイズが DATA_SIZE の整数型の配列 array の宣言 */ /* 配列のサイスは DATA_SIZE = 5 なので、5 個のデータが扱える */ int i; /* 添字変数 i を宣言 */ /* 5 個の数をまとめて入力 */ /* 配列の添え字には、「式」が利用できる */ /* ループ(for)で記述できる */ for ( i = 0; i < DATA_SIZE; i++ ) { /* 配列 array に数値を読み込む */ /* for ( i = 1; i <= DATA_SIZE; i++ ) を取らない */ /* プロンプト */ printf ( "%d 番目の整数値を入力してください : ", i + 1 ); /* 配列へのデータ入力 */ scanf ( "%d", &array[i] ); /* i = 0,1,..,4 < 5 = DATA_SIZE となるので、 配列を参照する「添え字」として、ループ制御変数 i が そのまま利用できる (同じマクロ名 DATA_SIZE が変数宣言と、ループで共有できる) */ } /* 入力された個々の値を 5 倍した物を出力 */ for ( i = 0; i < DATA_SIZE; i++ ) { printf ( "%d\n", array[i] * 5 ); /* 5 倍 */ } /* 入力された個々の値を 1/2 した物を出力 */ for ( i = 0; i < DATA_SIZE; i++ ) { printf ( "%d\n", array[i]/2 ); /* 2 分の 1 */ /* 「(1/2) * array[i]」はダメ */ /* 整数計算では (1/2) -> 0 になる */ /* 整数割り算になるので、小数点以下は切り捨て */ } return 0; }
#include <stdio.h> int main(int argc, char *argv[]) { /* 文字列を出力する代わりに、 文字列に相当する、整数値列を出力する */ printf ( "%d %d %d %d %d\n", 'H', 'e', 'l', 'l', 'o' ); /* 「Hello」文字列に対応する、ASCII Code 列を出力 */ printf ( "%d %d %d %d %d\n", 72, 101, 108, 108, 111 ); printf ( "%c %c %c %c %c\n", 72, 101, 108, 108, 111 ); /* %c は、整数値を、ASCII Code 表に従って、変換してくれる */ return 0; }
#include <stdio.h> /* * 二次元の点を表現するデータ型を考える * 直交座標系で、x, y の組み合わせ * x, y は実数(浮動小数点数) * コーディング規則決めた */ int main(int argc, char *argv[]) { double p1_x; double p1_y; /* p1 = <p1_x,p1_y> 順序対 */ p1_x = 1.0; p1_y = -2.0; /* p1 <= (1.0,-2.0) */ printf ( "p1_x=%f,p1_y=%f\n", p1_x, p1_y ); printf ( "p1=(%f,%f)\n", p1_x, p1_y ); return 0; }
#include <stdio.h> /* * 二次元の点を表現するデータ型を考える * 直交座標系で、x, y の組み合わせ * x, y は実数(浮動小数点数) */ /* 構造体としては、 struct { double x; double y; }; だが、これを使うときには、毎回、この構造体を書く必要があるので不便 # なので、「構造体名」を使うのが普通だが # この講義では、「構造体名」の導入は後回しで、 # typdef を使う typedef struct { double x; double y; } Point2D; -- 新しい型名 Point2D が利用できるようになる */ typedef struct { double x; double y; } Point2D; int main(int argc, char *argv[]) { Point2D p1; /* typedef を利用して、Point2D を宣言したので */ /* Point2D を型名として利用可能 */ /* これは、事実上 double p1.x: double p1.y; の二つの変数の宣言と同様 */ /* p1 = <p1.x,p1.y> 順序対 */ p1.x = 1.0; p1.y = -2.0; /* p1 <= (1.0,-2.0) */ printf ( "p1=(%f,%f)\n", p1.x, p1.y ); return 0; }
#include <stdio.h> /* * 二次元の点を表現するデータ型を考える * 直交座標系で、x, y の組み合わせ * x, y は実数(浮動小数点数) */ /* 配列で実現 */ int main(int argc, char *argv[]) { double p1[2]; /* 2 つの要素を持つ配列の宣言 */ /* p1[0], p1[1] が作られる */ /* 一般に double array[N]; と宣言すると、 double array_0; 0 から始まる double array_1; ... double array_N_1; N-1 まで の N 個の変数が作られる */ /* これは、実質 double p1_0; double p1_1; と同じ */ p1[0] = 1.0; /* 配列 p1 の 0 番目(最初の要素) */ p1[1] = -2.0; /* 配列 p1 の 1 番目(次の要素) */ /* p1 <= (1.0,-2.0) */ /* 配列は、同じデータ型の要素複数からなるので、 添え字で、その要素を参照できる */ printf ( "p1_x=%f,p1_y=%f\n", p1[0], p1[1] ); return 0; }
/* 構造体と配列の比較 */ typdef struct { int p0; int p1; int p2; } Struct3P; int main(int argc, char *argv[]) { Struct3P vs: int va[3]; int i; /* for 構文のループ制御変数 */ /* 構造体も、配列も 3 つの要素(変数)からなる */ /* 値の参照(すべての要素を 0 に初期化する) */ /* 構造体 (要素を個別に初期化する必要がある) */ vs.p0 = 0; vs.p1 = 0; vs.p2 = 0; /* 構造体の扱い(命令)は、順接で作られる */ /* 配列の場合 */ /* (案 1) 構造体と同じアプローチ */ va[0] = 0; va[1] = 0; va[2] = 0; /* (案 2) 添え字を利用してループで行うアプローチ */ for ( i = 0; i < 3; i++ ) { va[i] = 0; /* 同じデータ型(同じ値)なので、同じ命令でよい */ /* 要素が「添え字」で参照できる */ } /* 配列の扱いは、繰り返しで構築される */ /* 命令 データ型 ** 順接 構造体 ** 条件分岐 ??? (共用体) ** 繰り返し 配列 */ return 0; }
#include <stdio.h> /* * 二次元の点を表現するデータ型を考える * 直交座標系で、x, y の組み合わせ * x, y は実数(浮動小数点数) */ /* 構造体としては、 struct { double x; double y; }; だが、これを使うときには、毎回、この構造体を書く必要があるので不便 # なので、「構造体名」を使うのが普通だが # この講義では、「構造体名」の導入は後回しで、 # typdef を使う typedef struct { double x; double y; } Point2D; -- 新しい型名 Point2D が利用できるようになる */ /* 構造体を利用することにより、 コーディング規則を プログラムの中に取り込んだ */ typedef struct { double x; double y; } Point2D; void printPoint2D ( char *pointName, Point2D point ) { printf ( "%s=(%f,%f)\n", pointName, point.x, point.y ); } Point2D makePoint2D ( double x, double y ) { Point2D point; point.x = x; point.y = y; return point; } /* コーディングにかかわる変換 Point2D <-> 実数の組 を自動的にプログラム中で行うように記述できる */ int main(int argc, char *argv[]) { Point2D p1; /* typedef を利用して、Point2D を宣言したので */ /* Point2D を型名として利用可能 */ /* これは、事実上 double p1.x: double p1.y; の二つの変数の宣言と同様 */ /* p1 = <p1.x,p1.y> 順序対 */ p1 = makePoint2D ( 1.0, -2.0 ); /* p1 <= (1.0,-2.0) */ // printf ( "p1=(%f,%f)\n", p1.x, p1.y ); /* 二つの数の出力 */ printPoint2D ( "p1", p1 ); /* 「点」を出力 */ return 0; }
?R???s???[?^???????f?[?^???P???????????????A ?R?[?f?B???O??p?????A????????G???????A?u?v?Z?v????? -> ?R???s???[?^??u???\?v??????? ???????A?R?[?f?B???O??N????? ? ?R???s???[?^???A?P????f?[?^??????????????A ?l?????邵?????(??|) ?????A?R???s???[?^?????G??f?[?^(???????????????) ????????? ?R?[?f?B???O????????A?v?Z?@???点?鎖??????? ??T????n????u?f?[?^?\???v??b ?R???s???[?^????G??f?[?^??????????????\?????@???w?????? ?f?[?^?\??(1) ?\????:?P????f?[?^??g???????d?g?? -> ???w?I???u??????v?????d?g?? # ??????f?[?^??A???????A???l????????A???????W???????\??????? # ?? : ?????_??A??????g??????A?L??????A??????g???????????????l???????? ?\?????g???? struct { ?g??????f?[?^ } !! ????u?`???Atypedef ??g??????? typedef ??V?????^?????A ?????A????^???????鏈?????(?R?[?f?B???O???[???? ??????) ????????A?v???O???}???g???R?[?f?B???O??K?? ?????????A?V?????f?[?^?^???g????????? # ???w???A?W?????????????`????????u???v???? ?u?f?[?^?^?v???A?^???????(?l??W?????`???)?????????A ?????????????u??v????????????????? ?u?f?[?^?^?v??u????^????????????????v???? class ( ?I?u?W?F?N?g?w?????? ) ??T?O???? ?z?? : ?????^??f?[?^??(?????)??????? cf. ?\?????A(???????????A????????????..) ?????g??????鎖??????? ?\????????A???(???????????) => ??????????? : ?????????A???????????? ?v?Z?@????E??? ?\??????A?z???????u???????v?g???? ?u?Y?????v??????u?????@?\?v???g???? !! ?J??????g?????????p?????(?Y???????g??????..)????????_??????
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
なお「名前(P,Q,R,..)」の部分が同じ所には同じものが入ります。
Download : 20171027-01.c
/* * 課題 20171027-01 * * 20171027 20171027-01-QQQQ.c * * 複素数型の四則 */ #include <stdio.h> /* * 複素数型の定義と計算 * * 利用方法 * コンパイル * cc -Ic:\usr\c\include -o BASENAME.exe 20171027-01-QQQQ.c * 実行 * BASENAME */ #include <stdio.h> /* * 複素数型を表す Complex の定義 * * 複素数 z は、二つの実数 x, y を用いて * z = x + yi ( i は虚数単位 ) * と表現できる。 * C 言語では実数を表すのに浮動小数点数型の double を用いる * 型名 ( Complex ) を大文字で始めるのは「ソフトウェア概論ルール」 */ typedef struct { double real; /* 実部 */ double imaginary; /* 虚部 */ } Complex; /* 複素数型 */ /* * Complex make_Complex ( double x, double y ) * Complex 型の数を作り、返す * x, y -> z = x + yi */ Complex make_Complex ( double x, double y ) { Complex newComplex; /* 新しく作られる複素数 */ newComplex.real = x; /* 新しく作られた複素数の実部は x */ newComplex.imaginary = y; /* 新しく作られた複素数の実部は y */ return newComplex; /* 新しく作られる複素数を値として返す */ } /* * double real_part ( Complex z ) * Complex 型の数の実部を返す * z = x + yi -> x */ double real_part ( Complex z ) { return z.real; } /* * double imaginary_part ( Complex z ) * Complex 型の数の実部を返す * z = x + yi -> x */ double imaginary_part ( Complex z ) { return z.imaginary; } /* * print_Complex ( Complex z ) * Complex 型の数の出力 * z = x + y i だが、y < 0 の時は z = x - (-y) i となるように工夫 */ void print_Complex ( Complex z ) { if ( z.imaginary > 0.0 ) { printf ( "%f + %f i", z.real, z.imaginary ); } else { printf ( "%f - %f i", z.real, - z.imaginary ); } } /* * Complex add_Complex ( Complex z1, Complex z2 ) * Complex 型の数の足し算 * z1 = x1 + y1 i * z2 = x2 + y2 i * -> z1 + z2 = ( x1 + x2 ) + ( y1 + y2 ) i */ Complex add_Complex ( Complex z1, Complex z2 ) { Complex result; /* 複素数の和の実部は、実部の和 */ result.real = z1.real + z2.real; /* 複素数の和の虚部は、虚部の和 */ result.imaginary = z1.imaginary + z2.imaginary; return result; } /* * Complex sub_Complex ( Complex z1, Complex z2 ) * Complex 型の数の引き算 * z1 = x1 + y1 i * z2 = x2 + y2 i * -> z1 - z2 = ( x1 - x2 ) + ( y1 - y2 ) i */ Complex sub_Complex ( Complex z1, Complex z2 ) { Complex result; /* 複素数の差の実部は、実部の差 */ result.real = z1.real - z2.real; /* 複素数の差の虚部は、虚部の差 */ /* ** この部分を完成させなさい */ return result; } /* * Complex mul_Complex ( Complex z1, Complex z2 ) * Complex 型の数のかけ算 * z1 = x1 + y1 i * z2 = x2 + y2 i * の時 * z1 * z2 = (x1 * x2 - y1 * y2) + (x1 * y2 + x2 * y1) i */ Complex mul_Complex ( Complex z1, Complex z2 ) { Complex result; result.real = z1.real * z2.real - z1.imaginary * z2.imaginary; /* ** この部分を完成させなさい */ return result; } /* * Complex div_Complex ( Complex z1, Complex z2 ) * Complex 型の数の割り算 * z1 = x1 + y1 i * z2 = x2 + y2 i * の時 * z1 / z2 = ( x1 + y1 i ) / ( x2 + y2 i ) * = ( x1 + y1 i )( x2 - y2 i ) / ( x2 + y2 i )( x2 - y2 i ) * = ( x1 * x2 + y1 * y2) / ( x2^2 + y2^2 ) * + ( (- x1 * y2 + x2 * y1) / ( x2^2 + y2^2 ) ) i */ Complex div_Complex ( Complex z1, Complex z2 ) { Complex result; double denominator = z2.real * z2.real + z2.imaginary *z2.imaginary; /* 実部、虚部の割る数 |z2|^2 を予め計算しておく */ /* ** この部分を完成させなさい */ result.imaginary = ( - z1.real * z2.imaginary + z1.imaginary * z2.real ) / denominator; return result; } /* * print_result 演算結果を出力する */ void print_result ( Complex z1, Complex z2, char *operator, Complex z ) { print_Complex ( z1 ); printf ( " と、 " ); print_Complex ( z2 ); printf ( " との、%s は ", operator ); print_Complex ( z ); printf ( " です。\n" ); } /* * main */ int main( int argc, char *argv[] ) { Complex z1 = make_Complex ( 20.0, -15.0 ); /* z1 = 20 - 15i */ Complex z2 = make_Complex ( 1.0, 2.0 ); /* z2 = 1 + 2i */ /* 和の出力 */ print_result ( z1, z2, "和", add_Complex ( z1, z2 ) ); /* 差の出力 */ /* ** この部分を完成させなさい */ /* 積の出力 */ /* ** この部分を完成させなさい */ /* 商の出力 */ print_result ( z1, z2, "商", div_Complex ( z1, z2 ) ); return 0; }
$ ./20171027-01-QQQQ.exe 20.000000 - 15.000000 i と、 1.000000 + 2.000000 i との、和 は 21.000000 - 13.000000 i です。 20.000000 - 15.000000 i と、 1.000000 + 2.000000 i との、差 は 19.000000 - 17.000000 i です。 20.000000 - 15.000000 i と、 1.000000 + 2.000000 i との、積 は 50.000000 + 25.000000 i です。 20.000000 - 15.000000 i と、 1.000000 + 2.000000 i との、商 は -2.000000 - 11.000000 i です。 $
Download : 20171027-02.c
/* * 課題 20171027-02 * * 20171027 20171027-02-QQQQ.c * * 二次元行列型の定義と計算 */ #include <stdio.h> /* * */ #define DIMENSION 2 /* 二次元 */ /* * 行列 A は、2 x 2 = 4 の要素をもっている * * A = ( 1 2 ) = ( a[0][0] a[0][1] ) * 3 4 a[1][0] a[1][1] * */ typedef struct { double a[DIMENSION][DIMENSION]; /* 二次元の行列の要素は 2 x 2 */ } Matrix2D; /* Matrix2D 型の宣言 */ /* * Matrix2D make_Matrix2D ( double a, double b, double c, double d ) * 「行列」を作成する * * A = ( a b ) = ( a[0][0], a[0][1] ) * ( c d ) ( a[1][0], a[1][1] ) */ Matrix2D make_Matrix2D ( double a, double b, double c, double d ) { Matrix2D newMatrix2D; /* 新しい行列 */ newMatrix2D.a[0][0] = a; newMatrix2D.a[0][1] = b; newMatrix2D.a[1][0] = c; newMatrix2D.a[1][1] = d; return newMatrix2D; } /* * void print_Matrix2D ( Matrix2D ary ); * 「行列」を表示する (表示の都合上、常に独立した行に出力する) * Matrix2D ary; 二次元行列 */ void print_Matrix2D ( Matrix2D ary ) { int r; /* 行 ( row ) */ int c; /* 列 ( colomun ) */ for ( r = 0; r < DIMENSION; r++ ) { printf ( "(" ); for ( c = 0; c < DIMENSION; c++ ) { printf ( " %10.5f", ary.a[r][c] ); /* * [注意] %10.5f は %f と同じく浮動小数点数を出力するが * 「全体の桁数は 10 桁、小数点数以下は 5 桁にする」 * という「表示上の指定」も加わっている * 詳しくは google で「printf 書式」で検索 */ } printf ( " )\n" ); } } /* * Matrix2D add_Matrix2D ( Matrix2D a1, Matrix2D a2 ); * 「行列」の和 * * ( a b ) + ( e f ) = ( a + e b + f ) * ( c d ) ( g h ) ( c + g g + h ) */ Matrix2D add_Matrix2D ( Matrix2D a1, Matrix2D a2 ) { Matrix2D result; /* 計算結果 */ int r; /* 行 ( row ) */ int c; /* 列 ( colomun ) */ for ( r = 0; r < DIMENSION; r++ ) { for ( c = 0; c < DIMENSION; c++ ) { result.a[r][c] = a1.a[r][c] + a2.a[r][c]; } } return result; } /* * Matrix2D sub_Matrix2D ( Matrix2D a1, Matrix2D a2 ); * 「行列」の差 * * ( a b ) - ( e f ) = ( a - e b - f ) * ( c d ) ( g h ) ( c - g g - h ) */ Matrix2D sub_Matrix2D ( Matrix2D a1, Matrix2D a2 ) { Matrix2D result; /* 計算結果 */ int r; /* 行 ( row ) */ int c; /* 列 ( colomun ) */ for ( r = 0; r < DIMENSION; r++ ) { for ( c = 0; c < DIMENSION; c++ ) { /* ** この部分を完成させなさい */ } } return result; } /* * Matrix2D mul_Matrix2D ( Matrix2D a1, Matrix2D a2 ); * 「行列」の積 * * ( a b ) ( e f ) = ( a * e + b * g a * f + b * h ) * ( c d ) ( g h ) ( c * e + d * g c * f + d * h ) */ Matrix2D mul_Matrix2D ( Matrix2D a1, Matrix2D a2 ) { Matrix2D result; /* 計算結果 */ int r; /* 行 ( row ) */ int c; /* 列 ( colomun ) */ int i; for ( r = 0; r < DIMENSION; r++ ) { for ( c = 0; c < DIMENSION; c++ ) { double products = 0.0; /* a1 の r 行と a2 の c 列の内積の結果 */ /* a1 の r 行と a2 の c 列の内積を計算する */ /* ** この部分を完成させなさい */ result.a[r][c] = products; } } return result; } /* * print_result 演算結果を出力する */ void print_result ( Matrix2D a1, Matrix2D a2, char *operator, Matrix2D a ) { printf ( "%s の計算\n", operator ); print_Matrix2D ( a1 ); printf ( " と、 \n" ); print_Matrix2D ( a2 ); printf ( " との、%s は \n", operator ); print_Matrix2D ( a ); printf ( " です。\n\n" ); } /* * main */ int main( int argc, char *argv[] ) { /* a1 = ( 1 2 ) ( 3 -1 ) a2 = ( -3 1 ) ( 1 -2 ) */ Matrix2D a1 = make_Matrix2D ( 1.0, 2.0, 3.0, -1.0 ); Matrix2D a2 = make_Matrix2D ( -3.0, 1.0, 1.0, -2.0 ); /* 和の出力 */ print_result ( a1, a2, "和", add_Matrix2D ( a1, a2 ) ); /* 差の出力 */ /* ** この部分を完成させなさい */ /* 積の出力 */ /* ** この部分を完成させなさい */ return 0; }
123 987 456
$ ./20171027-02-QQQQ.exe 和 の計算 ( 1.00000 2.00000 ) ( 3.00000 -1.00000 ) と、 ( -3.00000 1.00000 ) ( 1.00000 -2.00000 ) との、和 は ( -2.00000 3.00000 ) ( 4.00000 -3.00000 ) です。 差 の計算 ( 1.00000 2.00000 ) ( 3.00000 -1.00000 ) と、 ( -3.00000 1.00000 ) ( 1.00000 -2.00000 ) との、差 は ( 4.00000 1.00000 ) ( 2.00000 1.00000 ) です。 積 の計算 ( 1.00000 2.00000 ) ( 3.00000 -1.00000 ) と、 ( -3.00000 1.00000 ) ( 1.00000 -2.00000 ) との、積 は ( -1.00000 -3.00000 ) ( -10.00000 5.00000 ) です。 $
Download : 20171027-03.c
/* * 課題 20171027-03 * * 20171027 20171027-03-QQQQ.c * * 整数型の配列を作り、それに 5 個のデータを入力し * その値を 5 倍にしたものと 2 分の 1 にした値を * それぞれ、画面に出力するプログラムを作りなさい * */ #include <stdio.h> /* * */ #define DATA_SIZE 5 /* データのサイズ (個数) */ /* * */ int main(int argc, char *argv[]) { int array[DATA_SIZE]; /* サイズが DATA_SIZE の整数型の配列 array の宣言 */ int i; /* 添字変数 i を宣言 */ for ( i = 0; i < DATA_SIZE; i++ ) { /* 配列 array に数値を読み込む */ /* プロンプト */ printf ( "%d 番目の整数値を入力してください : ", i + 1 ); /* 配列へのデータ入力 */ scanf ( "%d", &array[i] ); } /* 入力された個々の値を 5 倍した物を出力 */ for ( i = 0; i < DATA_SIZE; i++ ) { printf ( "%d\n", /* p:ここ */ ); /* 5 倍 */ } /* 入力された個々の値を 1/2 した物を出力 */ for ( i = 0; i < DATA_SIZE; i++ ) { printf ( "%d\n", /* q:ここ */ ); /* 2 分の 1 */ /* 整数割り算になるので、小数点以下は切り捨て */ } return 0; }
3 8 13 2 4
$ ./20171027-03-QQQQ.exe $