0. レポートの書き方表紙を付ける. コンピュータプログラミング入門 (x)(xは回), 実習日, 学籍番号, 氏名を記入すること. プログラムのアルゴリズムと実行結果, プログラム自体を付けること.1 つにまとめてホッチキス止めして提出すること. 以上を満たさないレポートは受け取らない. コンパイラとテキストエディタのインストール Windows ユーザ : gcc コンパイラ Cygwin インストール : https://www.sw.it.aoyama.ac.jp/2011/cp1/cygwin/ テキストエディタ Terapad のインストール : https://tera-net.com/ Mac ユーザ : gcc コンパイラ Xcode インストール : https://webaru.net/clang/mac-compiler-gcc-install/ テキストエディタ mi インストール : https://www.mimiai.net/ 1.C 言語基礎 (1) プログラム作成の流れプログラミングとは プログラムを作ることです 作ったプログラムは 一般的には ソフトウエアと呼ばれます ソフトウエアは コンピュータ (CPU, メモリ ハードディスクなど ) プリンターなどのハードウエアを使って いろいろな計算 画像処理などを実行します したがって ソフトウエア無しに コンピュータは動作しません 本演習では主に 画像処理のプログラムを作成します 皆さんが作成したプログラムに従って コンピュータが画像を処理し その結果を示してくれます ただし 皆さんが作ったC 言語 1
のプログラムはそのままでは 人間は理解できても コンピュータは理解できません 皆さんが作るプログラムはソースプログラム ( ソースファイル ) と呼ばれます C 言語では *.c という形式にファイルで作成します そのソースプログラムをコンピュータが理解できるようなデータ形式に変換することをコンパイルと呼びます コンパイルした後のファイルは マシン語の形式になっており 実行ファイルと呼ばれます Cygwin では *.exe という形式になります つまり ソースプログラムをコンパイルすることによって プログラムを実行することができます 実は コンパイルの後に リンク も実行されます リンクとは いろいろな標準関数 (printf( 表示する ), scanf( 入力する ), fopen( ファイルを開く ) など ユーザーが作る必要が無い標準的な関数 ) のオブジェクトファイル ( マシン語の形式に変換されている ) を皆さんが作ったプログラムに組み込むことです 以上のことをいかにまとめます (1) エディターを使って ソースプログラム (*.c) 作成する 本実習では エディタとして TeraP adを使います (2) コンパイラを使って ソースプログラムをマシン語に変換し 実行ファイルを作成する 本実習では コンパイラとして Cygwin の gcc を使います (3) 実行ファイルを使って プログラムを実行します (2) 基本プログラム 1 とコンパイル 実行の方法 1) 基本プログラム 1 以下のプログラムを TeraPad で作成してください. 字下げをうまく使ってプログラムを書いてください. #include <stdio.h> /* (1) */ int main( ) /* (2) */ { /* (3) */ printf("hi! How are you? n"); /* (4) */ /* (5) */ TeraPad でファイルの種類は C/C++ を選んで ****.c という名前にする **** は適当につける この例では hello.c という名前で保存します 保存先は Cドライブの arimura とします.Cygwin でのディレクトリ ( ホルダ ) の移動は以下のように行う. cd /cygdrive/c cd arimura 2) コンパイル方法 Cygwin の gcc を用いて コマンドラインで つぎのようにタイプし Enter を押します 以下の例では hello.c というソースプログラムをコンパイルして hello という実行ファイルを作ります $ gcc o hello hello.c (-o : この次にある引数は 実行ファイル名を書きます ) 3) 実行方法実行ファイル名をコマンドラインに書いて Enter を押します $./hello Hi! How are you? 2
4) 基本プログラム1の解説このプログラムはC 言語の基本中の基本プログラムです これを番号順に説明します 1 行目 :stdio.h はインクルードファイルと呼ばれるファイルです インクルードファイルにはいろいろあり 例えば この stdio.h にはC 言語プログラムで使う基本的な関数 ( 例えば 標準出力する関数 printf ファイルを開く関数 fopen データを読み込む関数 fread データを書き込む関数 fwrite など ) の定義が書かれています 他には 数学的な関数 sin( ), cos( ) などが定義されている math.h などもあります #include< > はインクルードファイルをここに読み込むという命令文です このファイルを読み込むこと ( インクルード ) をしないと これらの基本的な関数を使えません /* */ で囲んだものはコメント文として処理されます 2 行目 :C 言語のプログラムは必ず main 関数 1 つを持ちます main 関数の 3 と 5 行目の { の中にいろいろな 処理を書いていきます main 関数の { を忘れないようにしてください. 3 行目 :printf は画面に文字列 数を出力したいときに用います stdio.h に定義されている基本関数の一つで す Hi! How are you? n のようにダブルコーテーションで囲んだ文字列を出力します. n は改行するための コードです (3) 基本プログラム 2 エディタを使って 二つの整数の足し算をする プログラムを作成します プログラム例 ( 右側の説明はアルゴリズム ) を以下に示します #include <stdio.h> /* (1) stdio.h を読み込む */ int main(int argc, char *argv[]) /* (2) main 関数の定義 */ { int a, b, c; /* (3) 変数宣言 (a, b, c を使えるようにする )*/ a=atoi(argv[1]); /* (4) argv[1] の文字列を atoi の関数を用いて整数型の数値へ変換する */ b=atoi(argv[2]); /* (5) argv[2] の文字列を atoi の関数を用いて整数型の数値へ変換する */ c=a+b; /* (6) a+b を実行し その結果を c へ代入する */ printf("sum = %d n", c); /* (7) sum=c の値 ( 十進数 ) を printf 関数を用いて表示する */ 2) コンパイル方法 $ gcc o cal_sum cal_sum.c 3) 実行方法 $./cal_sum 10 20 sum = 30 このプログラムも C 言語のの基本プログラムです これを番号順に説明します 2 行目 : 上記で説明しましたように,C 言語のプログラムは必ず main 関数 1 つを持ちます この main 関数は 関数なので引数をとることができます 3
int main(int argc, char *argv[]) /* (2) */ int argc コマンドラインに並べた引数の数を入れる変数です 実行プログラムを含みます int は argc は整数型として使います という意味です char argv[ ] コマンドラインに並べた引数の文字列を入れる配列変数です 引数が順番に入ります char は *argv[ ] は文字列型として使います という意味です 例えば 以下のようにプログラムを実行すると $./cal_sum.exe 10 20 以下のように代入されます argc = 3 argv[0]= cal_sum argv[1]= 10 argv[2]= 20 3 行目 : ここにはプログラムで使いたい変数をまず記述します これを変数宣言といいます 例の場合 二つ の整数の合計を計算するので それらの変数を a と b とし 整数型の int 型で宣言しています C 言語の文の 終わりには必ずセミコロン ; を付けます 4 行目 :argv[1] と argv[2] に入っている文字列を整数に変換するために atoi( ) 関数を用いています ascii to integer の略です 戻り値は変換された整数になります 例の場合 a=atoi(argv[1]); では argv[1] に 10 が入っていたら a には整数 10 が代入されます 5 行目 : これは a と b を足して その結果を c に代入する と意味です c は a+b に等しいという意味で はありません 6 行目 : 文字列だけでなく,printf は画面に計算結果の数値を出力したいときにも使えます %d は出力するデ ータを符号付き整数 (int 型 ) と解釈して 10 進数に変換します この場合 c を 10 進数に変換して sum= の 次に出力します n は改行するためのコードです (4) 変数宣言 プログラムで使いたい変数をまず記述します これを変数宣言といいます 変数の型として主に以下のような ものがあります int short 整数型の変数に用いる 通常 4 バイト 符号付き (signed): -2 31 (2147483648) ~ 2 31 1 (2147483647) 符号無し (unsigned): 0 ~ 4294967296 int より短い整数型 通常 2 バイト 16ビット画像データを扱うときによく用いる 符号付き (signed): -32768 ~ 32767 符号無し (unsigned): 0 ~ 65535 4
float double char コンピュータプログラミング入門 実数型の変数に用いる 通常 4 バイト 1e-38~1e+38 倍長実数型の変数に用いる 通常 8 バイト 1e-307~1e+308 1 バイトの変数 ( 通常 文字列の変数 ) に用いる 通常 1 バイト (5) レポート課題 基本プログラム 2 で a と b に非常に大きな値を入力した場合, 足し算の結果が間違う場合があります. 理由を 考えて, 変数の型とオーバーフロー のレポートとして提出してください. 提出日は 次回の演習時 5
2. ループ演算 (1) (1) for 文 ~ 指定回数くり返す ~ 指定回数くり返す ということを得意とする制御文があります それが for 文です for( 式 1; 式 2; 式 3) 文 for 文は while 文の拡張版と考えて差し支えありません この文を while で書き直すとこうなります 式 1; while( 式 2){ 文式 3; 例を以下に示します #include <stdio.h> main() { int i; for(i = 0; i < 10; i++){ printf("i = %d n", i); printf("end. n"); この例は 一番オーソドックスな for 文の使い方です ではこのプログラムがどう動いているのか 順を追 って説明します while 文で書き直した図を見ながら理解してください 1. まず 式 1 を評価 ( 実行 ) するので i は 0 になります 2. 次に 式 2 を評価します この時 i は 0 ですから条件は成り立ちます 6
3. よって 文 を実行します つまり画面に i の内容が表示されます 4. 次に 式 3 を評価 ( 実行 ) つまりここでは i が 1 増えて i の内容は 1 になります 5. これをくり返して 式 3 によって i が 10 になったときに このループから抜け出します 適用例 1. 数学の は for 文で計算できます. 例えば, 平均値 (f = & ' f ' ()& () や分散 (σ, = & ' -f ' ( f /, ()& ) を求めると き. 2. 画像ファイルからピクセル値をピクセルごとに読み込むときに用いる. 3. フィルタ処理 ( 畳み込み積分 ) の計算 課題 1 1 から 10 までの足し算を求めてみる &3 S = 1 i ()& 課題 2.0.1 を 100 回足してみる ( 実数型の float と double, まるめ誤差 ) &33 S = 1 0.1 ()& レポート課題 課題 2 の結果に基づいて, まるめ誤差についてまとめ, レポートとして提出してください 7
3. ループ演算 (2) コンピュータプログラミング入門 課題 1 for 文を用いて char 型 short 型 int 型の変数における 階乗 (n! = てください ただし n=20 としてください ( 階乗計算 変数の型とオーバーフロー ) : ()& i = 1 2 3 n) を求め 課題 2 ネイピアの数 ( 自然対数の底 )e(2.71828 18284 59045 23536 02874 71352 ) を マクローリン展開 を使って 求めてみる (for 文 ) マクローリン展開 B f(x) = @ 1 n! f(:) (0)x : :)3 B e D = 1 x( i! ()3 = 1 + x 1! + x, 2! + xf 3! + + x: n! +, < x < : e = 1 1 = 1 + 1 i! 1! + 1 2! + 1 3! + + 1 n! ()3 上記の式と for 文を使って ネイピアの数 ( 自然対数の底 )e の値を求めてください レポート課題 半径 1 の 4 分の 1 円の面積を求めることで, π の値を求めるプログラムを作成してください. 二乗は x*x か pow(x, 2) です. は sqrt( )() 内は double 型です. 8
4. 文字列と制御文 課題 1 名前を表示してみる ( 配列 ) 配列 char name[10]; /* 10 個の name の入れものができる つまり name[0], name[1],,,,, name[9] で name[9] には NULLというコードが入る NULL はここで終わりという意味 したがって 入力したい文字数 +1 個分の入れ物が必要 例えば strcpy(name, Hide ); とすると name[0] => H name[1] => i name[2] => d name[3] => e name[4] => NULL 例を以下に示します #include <stdio.h> #define MAX_NAME_LENGTH 30 main() { int i; char name[max_name_length]; strcpy(name, "Your Name"); for(i = 0; i <= strlen(name); i++){ printf("name[%d] => %c n", i, name[i]); printf("end. n"); 9
上記のプログラム中の strcpy(name, "Your Name"); において "Your Name" のところを自分の名前に書き換えて ください ただし名前は半角英数字で入力してください また for 文を変更して 名前を逆の順序で作成してください ただし NULL 文字は表示させない < 表示例 > name[3] => e name[2] => d name[1] => i name[0] => H 課題 2 double 型の配列に適当な 5 個の実数を入れて その中の最小値を求めてみる ( 配列 for 文と if 文 ) if 文 制御の流れを分岐させるときの方法の一つとして if 文があります 一般的な構文は if( 式 ) { 文 ; 式が真ならば文を実行 (0 以外は真 ) if( 式 ) { 文 1; else { 文 2; 式が真ならば文 1 を実行 偽ならば文 2 を実行 10
式としては一般的には次のようなものになります 式 1 関係演算子式 2 式 1 論理演算子式 2 具体的には次のようなものが考えられるでしょう A = = B A が B に等しいならば真 A!= B A が B に等しくないならば真 A < B A が B より小さいならば真 A >= B A が B 以上ならば真 式 1 && 式 2 式 1 かつ式 2の両方成り立つならば真 式 1 式 2 式 1 または式 2のどちらか成り立つならば真 最大値を求めるプログラムの例 #include <stdio.h> main() { int i; double MaxValue; double value[5] = {1.2, 3.4, 2.3, 5.1, 0.7; MaxValue = 0.0; for(i = 0; i < 5; i++){ if(maxvalue < value[i]){ MaxValue = value[i]; printf("value[%d] => %f n", i, value[i]); printf("maximum value : %f n", MaxValue); 上記の最大値を求めるプログラム例をヒントにして 最小値を求めるプログラムを作成してください 課題 3 上記の最大値を求めるプログラム例を修正して 5 個の実数の平均値を求めるプログラムを作成してください 平均値の式はfK = 1 N f N i)1 iです. 11
5. ループ演算と制御文 課題 1 以下の 10 人分の身長のデータに対し double 型の配列を用い 平均値 標準偏差 (σ = Q & ' -f ' ( f /, ()& ) を求め 平均値で2 値化するプログラムを作成してください (if 文, sqrt 関数, pow 関数 ) 150.1, 186.4, 174.2, 189.9, 169.6, 159.2, 163.8, 156.9, 173.2, 167.4 (1) ルートの関数は sqrt( ここには double 型の変数を入れる ) です たとえば A = sqrt(2.0); printf( A = %f n, A); と書くと 実行結果は A=1.414.. と表示されるはず (2)xのy 乗を求めるために pow を使います Z = pow(x, y); Z, x, y は すべて double 型です 注意! sqrt pow を使うために math.h をインクルードします コンパイルする際は 最後に lm を追加 例 ) gcc o adai7 adai7. c lm 課題 2 上記の課題 1 で作成したプログラムにおいて 平均値を求める関数を作成して プログラムを書き 換えてください ( 関数 ) 関数 C 言語でのプログラムは 関数 という小さなプログラムの集まりで構成されます main() も関数ですし printf() や上記の課題で用いた pow() や sqrt() も関数です 関数とは いくつかの引数を受けて計算を行い その結果を返すもので 何らかの値を与えると それに応じた値が返ってくる 関数は計算結果としてなんらかの型 (int や char double など ) を持つ値を返します しかし 型のない関数 ( つまり値を返さない関数 ) も存在します printf() などの標準関数は すでに用意されている関数なので プログラム中で単に呼び出すだけでよいのですが ( 実際には #include <stdio.h> によって標準関数についての読み込みが必要 ) 標準関数に用意されていない関数は 自分で作らなければなりません 関数の定義は以下のとおりです [ 関数の型 ] 関数名 [ 引数の宣言 ] { 関数本体 [return 返す値 ] 関数の型とは 関数が返す値の型で 関数が扱う変数の型ではありません 関数名は printf などといった名前です printf 関数に渡していたデータを引数といいます 12
関数が返す値を決めるものが return です 値を返すことで関数の働きは終了するのですから この return 文で関数の実行が終了します 関数が正しく設定され 利用されているかチェックするものに関数プロトタイプ宣言があります 関数プロトタイプ宣言とは 関数の引数の数とその型 そして関数自身が返す値の型をあらかじめ宣言することです コンパイラは 関数と関数プロトタイプ宣言されたものと比較し 変数の数や戻り値の型が等しくなければエラーを出します 2 ページの 二つの整数の足し算をするプログラム を例に 足し算 の関数を作成する例を示します #include <stdio.h> /* (1) */ int main(int argc, char *argv[]) /* (2) */ { int a, b, c; /* (3) */ a=atoi(argv[1]); /* (4) */ b=atoi(argv[2]); c=a+b; /* (5) */ printf("sum = %d n", c); /* (6) */ 手順 1. 関数名 関数の返り値 引数を決める 例 ) 関数名 wa 関数の返り値の型 int 引数の型 int 引数の個数 2 個 手順 2. 関数を定義する 前頁の 関数の定義 を参考に定義する int wa(int a, int b){ 手順 3. 関数を main() 関数の外側に書く 手順 4. 関数本体を作成 関数 wa は 二つの int 型の引数を足して int の値を返す という役割なので 関数本体は以下のようになる int wa(int a, int b){ int c; c = a+b; return c; 手順 5. プロトタイプ宣言を関数の前に書く 関数名 関数の戻り値の型 引数の型 個数を書く int wa(int a, int b); 手順 6.main 関数で呼び出す 13
6. 演習 (1) コンピュータプログラミング入門 課題 1 角度 θ[ 度 ] を入力し sinθ,cosθ,tanθ の計算結果を出力するプログラムを作成してください C 言語での三角関数は 以下のとおりです double sin(double x) double cos(double x) double tan(double x) 引数の単位はラジアンです 数学関数を使用するためには #include <math.h> として math.h というヘッダをインクルードする必要があります また コンパイル時は最後に lm を追加 例 ) gcc o adai9 adai9. c lm 課題 2 次の微分方程式をオイラー法とルンゲクッタ法を使って解いてください またそれぞれの方法によって得られた数値解の精度を理論値 ( 解析的に解いた解の式から求めた値 ) と比較してください dx = x x( 0) = 1, 0 t 1, h = 0. dt 05 常微分方程式の数値計算物理学や工学において 導関数を含む関係式が与えられているとき このような関係式を満たす関数を求める必要がしばしば生じます 導関数を含む関係式から 関数そのものを求めるとき 導関数を含む関係式を微分方程式といい 微分方程式に含まれる導関数が 一つの変数による微分であるとき 常微分方程式といいます 常微分方程式の数値解は, 以下のようにして求めます dx = dt f ( x, t) t = 0 で x=x0 を数値的に解くということは t = t 0 = 0 で x=x 0 から出発して,t = t 1, t 2,, t,.., t n での x の数値 x = x 1, x 2,, x,.., x n を求めていくことである ただし t - t h とする オイラー法 x = x + hf ( x + t ) + 1 i +1 i = ルンゲクッタ法 1 x + 1 = x + h( 1 + 22 + 23 + 6 4 ) 14
15 ), ( ) 2, 2 ( ) 2, 2 ( ), ( 3 4 2 3 1 2 1 h t h x f h t h x f h t h x f t x f + + = + + = + + = =
7. 演習 (2) 課題 1 以下に示す範囲の f(x) をフーリエ級数展開してみましょう また級数において第 N 項まで求める 際 N=10 20 30 とした場合の結果を比較してください フーリエ級数展開 区間 [-p, p] における積分可能な関数 f(x) は次のように展開することが可能です このように表現されるとき 上式の a n b n は以下のように与えられる < 手順 1> a 0 a n b n を求める < 手順 2> a 0 a n b n をフーリエ級数展開の式に代入し 関数 f(x) を sin と cos で表現する 16