Download : sample-001.c
/*
* 2019/11/15 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
/*
* 2019/11/15 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 です。 $
/*
* 課題 20201030-01
*
* 20201030 20201030-01-QQQQ.c
*
* 極座標で表現されている点 Q から、それと原点に対して対称な点 R を求める
*
* 点 P <=> name:(r,a)
* name : 点の名前 ( 一文字 )
* r : 原点からの距離
* a : 原点とその点を結ぶ辺と x 軸がなす角
* この二つの浮動小数点数で、一つの点を表現する
* P と <name,r,a> の対の対応は、プログラマの頭の中にしかない
*/
#include <stdio.h>
#include <math.h> /* M_PI (円周率) を利用するので.. */
/*
* void print_polar ( char name, double r, double a )
* 極座標の表示
* char name; 点の名前
* double r; 極座標の動径
* double a; 極座標の偏角
*/
void print_polar ( char name, double r, double a ) {
printf ( "点 %c の極座標は (%f,%f) です。\n", name, r, a );
}
/*
* main
*/
int main( int argc, char *argv[] )
{
/*
点 Q : 原点から 7 離れており、角度は x 軸に対して 60 度 ( Pi/3 )
*/
double Q_polar_radius = 7.0; /* 点 Q の極座標系の動径 */
double Q_polar_argument = M_PI/3; /* 点 Q の極座標系の偏角 */
/* 点 Q の名前は 'Q' */
double R_polar_radius; /* 点 Q と原点対称な点 R の動径 */
double R_polar_argument; /* 点 Q と原点対称な点 R の偏角 */
/* 点 R の名前は 'R' */
/*
* 点 Q の表示
*/
print_polar ( 'Q', Q_polar_radius, Q_polar_argument );
/*
* 点 R の計算 ( R の位置を求める )
* Q から
* R の動径 => R_polar_radius の値
* R の角度 => R_polar_argument の値
* を、それぞれ求める
*/
/* 対称なので原点から距離は同じ */
R_polar_radius = Q_polar_radius; /* R の動径は Q の動径と同じ */
/* 180(π)だけ回転 */
R_polar_argument = Q_polar_argument + M_PI;
/* R の角度は、Q の角度に回転する角度を加えるだけ */
/*
* 点 R の表示
*/
print_polar ( 'R', R_polar_radius, R_polar_argument );
return 0;
}
/*
* 課題 20201030-02
*
* 20201030 20201030-02-QQQQ.c
*
* 構造体を利用し、平行移動を行う関数を作成する
* 点 P <-> (x,y) : 直交座標で表現する
* => 構造体を利用する
* C 言語上でも、「対」が保証される
* 他の人間(三日後の自分)にも分かりやすい
* C コンパイラの支援が得られる
* => 代入の記述を代行してくれる
*/
#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 の動径
* 対応させても、「プログラム上」はなんら問題ない
* (正く動くように作る事ができる)
*/
/*
データ型 => データ構造 (struct) + その扱い方(命令)
pt <-> (x,y)
pt.x を pt の x 座標として扱う
pt.y を pt の y 座標として扱う
<数学>
空間 => 集合と演算子
cf. 線形空間 : ベクトル集合, 定数倍と和
直交座標系による点の表現
*/
typedef struct { /* typedef を利用するので構造体名は省略 */
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; /* 返す値を入れる変数 */
/* x 軸方向に delta_x だけ平行移動した result.x を得るには、
pt の x 座標に delta_x を加えればよい */
/*
result.x と result.y を求めて、
result を結果と返す
!! C 言語では関数の返す値は1つだけ
!! 構造体を利用する事により、
!! 形式的には、1つの値なのに、
!! 二つの値(x,y)を返すという事が可能になる
*/
result.x = pt.x + delta_x;
/* y 軸方向に delta_y だけ平行移動した result.x を得るには、
pt の y 座標に delta_y を加えればよい */
result.y = 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 の値の初期化 */
/* 構造体の初期化をするために、
個々のメンバーを、別々に初期化する必要がある */
p1.x = 1.0; /* p1 = ( 1.0, 2.0 ) */
p1.y = 2.0;
/* 構造体の値の操作が => 順接になっている */
/* (一つの)値の代入が => 二つの値の代入の順接 */
/* (一つの)値の表現が => 二つの値の表現の構造体(直積) */
/* 平行移動 */
printf ( "点 " );
/* 構造体は引数で、そのまま渡せる */
print_point ( p1 );
/*
関数 print_point の仮引数変数 pt に p1 の値が代入される
pt = p1;
pt.x = p1.x;
pt.y = p1.y;
*/
printf ( " を x 軸方向に %f, y 軸方向に %f 移動した点は ", dx, dy );
/* 構造体は、値としても取り出せるし、普通に代入もできる */
p2 = shift_point ( p1, dx, dy );
/* p1 を、x 軸方向に dx, y 軸方向 dy だけ平行移動 */
print_point ( p2 );
printf ( " となります。\n" );
return 0;
}
/*
* 課題 20201030-03
*
* 20201030 20201030-03-QQQQ.c
*
* 3 次元ベクトルの差の計算
*
*/
#include <stdio.h>
/*
* 3 次元ベクトル
* 三つの要素(数値)からなるだけでなく、
* 定数倍や、和(差)が使える
* => 線形空間になる
*/
typedef struct { /* 3 次元ベクトル */
double x; /* x 要素 */
double y; /* y 要素 */
double z; /* z 要素 */
} Vector3D; /* 新しい型 : Vector3D */
/*
* 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; /* 計算結果(差)を收める変数 */
/*
v1 = ( x1, y1, z1 )
v2 = ( x2, y2, z2 )
=>
v1 - v2 = ( x1 - x2, y1 - y2, z1 - z2 )
result.x, result.y, result.z
result = src - dst; <= このようには書けない
*/
result.x = dst.x - src.x;
/* x 成分の計算 */
result.y = dst.y - src.y;
/* y 成分の計算 */
result.z = dst.z - src.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;
}
#include <stdio.h>
/*
* キーボードから入力された
* 文字を、大文字に変換して出力する
*/
int main(void) {
int ch;
printf ( "大文字を一文字に入力してください : " );
ch = getchar();
printf ( "入力された大文字(%c) を小文字(%c)に変換しました。\n",
ch, ch + 32 );
/*
+32 をすると、大文字が小文字変換される
=> ASCII Code から出てくる性質
=> もし、他のコーディング規則を利用すると、
このプログラムは意味がなくなる
プログラムを作成するには、コーディングから決める
コーディングの良しあしによって、
プログラムの作成さの難易度が変わる
コーディングの重要さ
*/
return 0;
}
#include <stdio.h>
/*
配列の利用例
複数の変数の代用
*/
int main(void) {
int a[3]; /* a[0] ? a[2] が宣言 => int a0,a1,a2; */
int i;
/* 初期化 */
a[0] = 1; /* 配列の要素は、それぞれ別の変数としてふるまう */
a[1] = 3;
a[2] = 5;
/* 配列は、繰り返し ( for 構文 ) との */
/* 配列のすべての要素を出力 */
for ( i = 0; i < 3; i++ ) { /* for ( i = 1; i <= 3; i++ ) */
printf ( "a[%d] = %d\n", i, a[i] );
}
return 0;
}
前回の内容
データ構造の必要性
プログラムを作成
命令を並べて、目的とする機能を実現する
三つの制御構造
順接 : 命令を順に実行する
条件分岐 : 条件によって、複数の命令を切りかえる
繰り返し : 条件が成立する限り、命令を繰り返す
=>
基本的な命令を組み合わせる事により、
任意の機能が実現できる
=>
C 言語で、これらをどのように表現するか ?
順接 => 並べるだけ
条件分岐 : if 構文 / switch 構文
繰り返し : 再帰構造 / while / for 構文
分割統治
目的を、副目的に分割する
プログラムを作成する目的
プログラムを使って、現実の機能を実現したい
現実とコンピュータの対応関係が必要
現実の対象が複雑
コンピュータの扱うデータも複雑
データを設計する <=> プログラム構造の設計
C 言語 : 手続き型言語
=> 命令の組み合わせ(手続き)でプログラム
<=> 対象となる(現実のモノに対応した)データの組み合わせ
=> オブジェクト指向
対象を記述すれば.. (自然に..) 対象が相互作用して、
目的の機能を実現する(シミュレーションの発想)
=> データ構造
データ構造 (1)
コーディング : 数値で情報を扱う原理
(現実の)情報と(コンピュータの中の)数値の対応関係
例: ASCII Code
現実の「文字」 <=> コンピュータの「整数値」
'A'=>'a' <=> +32
=> 情報処理が、計算で(間接的に..)表現可能になる
コードからデータへ( => オブジェクト )
プログラム = データ構造 + アルゴリズム
データ構造を作る
複数の「単純なデータ」の組み合せ
で「複雑なデータ」を作る仕組み
構造体 : 直積空間の構成
n 個の(単純な/基本となる)データの組み合わせで、
複雑なデータを表現する手段
=> 直積空間 ( A, B => A x B = { <a,b> | a \in A, b \in B } )
構文:
a \in int, b \in double => struct s = int x dobule
struct s {
int a;
double b;
};
typedef : 型に名前を付ける仕組み
typedef struct s {
int a;
double b;
} S;
struct s に S という名前を付ける
=> 以下、S と書けば、struct s と同じ意味
要素の取り出し
S = int x double = { <a,b> | a \in int, b \in double }
s \in S
s <-> <a,b> ( 整数値と浮動小数点の組 )
s.a -> s を構成する要素の整数の部分
s.b -> s を構成する要素の浮動小数点の部分
代入
S s; S 型の変数
S t;
s = t; S 型の変数での代入ができる
=> 代入ができる
=> 関数の引数や、返り値に S が使える
# できない事
# その型の定数(表現):リテラルが表現できない
S s = <1,0.1>; <= このような表現ができない
==
配列
同じ型のデータが多数並んだ物を表現する仕組
cf. 構造体: 異なる型が(少数)並んだ物を表現する
# 配列の方が「効率が良い」事が多い
# <= 繰り返しと相性の良さ
# 配列と同じ扱いで、「ポインタ型」の扱いができる
# => 配列が「多用」されている
例: double a0,a1,a2 -> double a[3] /* a[0], a[1], a[2] */
配列名 : データの並びが入る変数の代表名
添字 「'[' + 整数値 ']'」を付けて、要素が参照できる
配列の宣言の時、配列の要素の個数 N を指定して
型 配列名[N];
=> N 個の変数が宣言
型 配列名[0], 配列名[1], .., 配列名[N-1];
C 言語では添え字は 0 から始まる
配列の宣言
配列を利用する(宣言する)場合は、「配列名[サイズ]」の形にする
サイズ個数の変数がまとめて用意される
参照する場合は 0 ? サイズ-1 まで
例:
int ary[10];
とすると
ary[0] ? ary[9] = ary[10-1]
が使える
<<重要>>
配列の要素を参照する場合は、
配列名[要素番号]
の形で、参照するが、
要素番号の所には、「整数『式』」が書ける
『式』には、変数を含める事ができる
同じ「表現」でも「変数の値」変更する事により、
異なる「動作」をさせる事ができる
!! cf. 関数の引数
!! a1 は 「a『1』」という具体的な数値(1)を指定する
!! a[1]は「i=1; a[i]」という間接的に(変数を経由して)指定できる
!! => 柔軟性が出てくる
!! 配列 vs 関数
!! a[x], f(x) : ともに変数を利用して、(同じ表現で)異なる意味になる
!! 配列 : 変数なので、予め代入した値が得られる
!! => 低機能
!! 関数 : 命令ががけるので、高度な計算結果を返す事ができる
!! => 高機能
!! => 配列の機能を関数で実現する事も可能
!! 配列は変数なので、「代入」が可能
!! 関数は、代入文の右にしかかけない
!! 配列は、代入可能なので、代入文の左にもかける
!! # 「変数」は「『左辺値』を持つ」
配列プログラミング (集合操作)
配列 vs 集合
配列は、複数の同じ型の変数(配列の要素)をまとめたもの
集合の要素は、値そのもの
例: 二次元ベクトルの要素
(1,2) : 値の組み合わせ
配列(データ構造/構造体も同様..)
値を保存できる「変数」を用意し、
その変数に「値を保持させる」事により、
その変数で、値(集合の要素)を差し示す事ができる
cf. 基本型の場合は、変数を利用せずに、値が表現できる(リテラル)
例:
整数値の「1」は、直接 C 言語で「1」と表現できる
文字の「A」は、直接 C 言語で「'A'」と表現できる
!! 「『集合』の『要素』」は、『集合』に含まれる『値』の事
!! 例 : A = { 6 の約数 } = { 1, 2, 3, 6 }
!! A の要素は 1, 2, 3, 6 の四つ
!!「『配列』の『要素』」は、『配列』の一部である個々の変数の事
!! 例 : int a[4] => 配列 a の要素 a[0], a[1], a[2], a[3]
!!「『構造体』の『要素』」は、『構造体』の一部である個々の変数の事
!! 例 : struct { int x; int y } s;
!! 構造体 s の要素 s.x,s.y
配列の個々の要素は、同じ型の値を保持する変数
一つの配列(が保持する値の集まり) は、その型の「集合」を表す
!! 配列のサイズと同じ(あるいはそれ以下)の要素からなる
!! 例 int a[3];
!! a <-> { 1, 2, 3 }
!! <-> { 123, 456, 789 }
!! !! 集合のサイズは、可変
!! !! => 配列サイズは、最初に固定する必要がある
!! !! # 後で、ポインター型の所で、可変な配列(のようなもの)が利用できる
集合操作
{1, 2, 3} -> {2, 4, 6} # すべての要素を 2 倍
{1, 2, 3} -> {4, 5, 5} # すべての要素に 3 を加える
配列の要素(複数)への操作を「繰返し」で表現する
「『集合全体』への操作」が、「個々の要素の操作の『繰返し』」になる
<注意>
配列は、集合のように要素数が変化したりはしない
配列の異る要素(変数)が同じ値を持つ事もある
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20201106-01.c
/*
* 課題 20201106-01
*
* 20201106 20201106-01-QQQQ.c
*
* 複素数型の四則
*/
#include <stdio.h>
/*
* 複素数型の定義と計算
*
* 利用方法
* コンパイル
* cc -Ic:\usr\c\include -o BASENAME.exe 20201106-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;
}
$ ./20201106-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 : 20201106-02.c
/*
* 課題 20201106-02
*
* 20201106 20201106-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
$ ./20201106-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 : 20201106-03.c
/*
* 課題 20201106-03
*
* 20201106 20201106-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
$ ./20201106-03-QQQQ.exe $