コンピュータ基礎実験 第10回 コンピュータープログラミング (C言語)(7) 1.繰り返し処理、配列(復習) 2.乱数 繰り返し処理(復習) コンピュータでは、少しずつ条件を変えながら同 じ処理を繰り返す状況がよくでてきます。 C言語では、繰り返し処理を行うために「for文」、 「while文」が用意されています。 「for文」:「初期値」を与え、与えられた条件を満たし ている間、同じ処理を繰り返す 「while文」: 特に初期値を設定せず、与えられた条件 を満たしている間、同じ処理を繰り返す 繰り返し処理 For文 for (初期値の式; 条件式; ループの終わりに実行する式){ 文 } While文 While文 (初回も条件チェック) while (式){ 文 } do~while文 (初回は条件チェック無) do{ 文 } while (式); 前回課題9-6:ex9-6.c 前回課題9-6:自然対数の底e(=2.71828…)は次の無限級数で与えられ る。 1 1 1 1 1 1 e 1 1 2 1 3 2 1 4 3 2 1 i 0 i! 上の無限級数の初めのn項目までを計算するプログラムを作成せよ。 このとき、小数点以下10桁(”%.10f”)で出力せよ。 (→ ex9-6.c) WEB上でeの値を調べ、n=1, 5, 10, 20について自分のプログラムで 計算し、収束する様子を確認せよ。(double変数を使用せよ) 注)「0!=」1です。 4 前回課題9-6解答例 #include <stdio.h> int main(void) { int i,n; double x=1, sum=0; scanf("%d",&n); for(i=1;i<=n;i++){ if(i!=1){ x*=(double)(i-1); } sum+=1/x; } printf("e=%.10f\n",sum); n!を記憶する変数として「x」を宣言 n!はn=0の時、特殊なので扱いを別にする n=0のとき「n!=0!=1」 n!は前回ループの時(n-1)!を求めてあるの で前回の値にn(=i-1)を掛ければよい 変数「sum」にどんどん1/n!を足していく 初期化「sum=0」を忘れるな! return 0; } 5 配列(復習) 「繰り返し処理」とともに用いると、非常に便利な 機能が「配列」という機能です。 「配列」は、ベクトルや行列の成分のように、複 数の数字の組み合わせを「添え字」を用いて表 す「変数」(数字を記録する箱)のセットです。 a[0]、a[1]、a[2]…のようにカギ括弧を使う。添え字は0から b[0][0]、b[0][1]…: 添え字が2変数 C[0][0][0]、c[0][0][1]…:添え字が3変数 文字列も配列を利用して扱います(New) 配列の使用法 配列の宣言 int a[12]; float b[35]; double c[10]; など [ ]内は配列のメンバー数 初期値の代入 int a[3]={3,-2,1}; 宣言時に初期値を代入できる int a[]={3,-2,1}; 初期値代入の場合はメンバー数省略可 宣言時以外ではいっぺんに代入するのは不可能 配列の参照 [ ]内に参照したい番号を書いて参照する(0始まり) int a[3]={1,-2,3}; のとき a[1]には「-2」が記憶されている 文字列 文字列はchar型変数の配列を利用して実現 しています char h[]=”Hello world!\n”; * アドレス(箱番号) 0 値 325 1 2 2441 -523 3 ’H’ 4 ’e’ 5 ’l’ 6 ’l’ 7 ’o’ ‥‥ ’\n’まで h ⇒3 h[0] ⇒ ’H’ h[1] ⇒ ’e’ 「h[]」と名付けた *配列メンバー数は初期値代入のため省略されている メンバー数は14個、 「\n」の後に文字列の終わりを示す「終 端文字」が加えられる 例題10-1文字列と配列:ex10-1.c #include <stdio.h> int main(void) { char h[]=”Hello world!\n”; int i; printf(”%s”,h); printf(”文字列の先頭アドレスは%uです。\n”,(unsigned int)h); for(i=0; i<13; i++){ printf(”%d番目の文字は、「%c」です。\n”,i,h[i]); } return 0; } 9 例題10-2文字列の利用:dq2-1.c #include <stdio.h> #include <unistd.h> printf("%s%s",quest1,yesno);/*旅?*/ scanf("%d",&a); if(a==1){ sleep(2); printf("%s%s%s%s",name_m1,event1,quest2,yesno);/*メタル出現*/ scanf("%d",&a); if(a==1){ /* メタルと戦う */ battle1(name,name_m1); } else{ /* メタルと戦わない */ printf("%s",event2); sleep(2); printf("%s%s",name,event3); sleep(2); } } else{ printf("%s%s",name,event3); sleep(2); } printf("%s%s%s%s",king1,name,king2,king4); return 0; int intromusic(void); int battle1(char name[], char name_monster[]); int main(void) { char name[20]; char king1[]="「王様」ゆうしゃ "; char king2[]=" よ "; char king3[]="りゅうおうを たおすのじゃ\n"; char king4[]="しんでしまうとはなさけない\n"; char quest1[]="たびにでる?\n"; char quest2[]="たたかう?\n"; char quest3[]="右へいく?\n"; char name_m1[]="メタルスライム"; char name_m2[]="キラーマジンガー"; char event1[]="があらわれた\n"; char event2[]="そのあと なにもであいませんでした\n\n"; char event3[]="はへいぼんないっしょうをおえ、なくなりました\n\n"; char yesno[]="1. はい 2. いいえ\n"; } int i,a; intromusic(); printf("名前を入れてください: "); scanf("%s",name); printf("\n\n"); printf("%s%s%s%s",king1,name,king2,king3); 10 例題10-2文字列の利用:dq2-2.c #include <stdio.h> #include <unistd.h> int battle1(char name[], char name_monster[]) { printf("ちゃららっ\n\n"); sleep(1); printf("ゆうしゃ %s のこうげき\n",name); sleep(2); printf("%sに25のダメージ\n\n",name_monster); sleep(2); printf("%sのこうげき\n",name_monster); sleep(2); printf("ゆうしゃ %s に35のダメージ\n\n",name); sleep(2); printf("ゆうしゃ %s はしんでしまった\n\n",name); sleep(2); return 0; } int intromusic(void) { char m1[]="ちゃーちゃ"; char m2[]="ちゃちゃちゃ"; char m3[]="ちゃ"; char m4[]="ちゃん"; printf("%s %s%s %s %s %s\n",m1,m2,m3,m2,m2,m3); sleep(2); printf("%s %s %s\n\n",m1,m2,m4); sleep(3); return 0; } 11 乱数(random number) コンピューターでは、サイコロの様に毎回ランダ ムに変化する数字を生成することができます 毎回ランダムに変化する数を「乱数」といいます C言語では乱数を生成する関数として「rand()」 関数が標準で用意されています 「rand()」はC言語が開発された時から用意されているので、 設計が古く、ランダムさの性能がよくありません 必ず用意されているとは限りませんが、もし「random()」関 数が用意されている場合はこちらを使った方がよい ■ 乱数の出し方 /* 乱数 ex10-3.c */ #include <stdio.h> #include <stdlib.h> 「rand()」関数が宣言 されている [ 出力例 ] int main(void) { int i, rn ; for(i=0;i<10;i++){ rn=rand(); printf("%d¥n",rn); } return 0; } 33613 564950497 1097816498 1969887315 1404212 940422543 202055087 768218108 770072198 1866991770 13 「rand()」関数の性質 プログラムを繰り返すと毎回同じ乱数の列が得 られる 本当の乱数ではない!「疑似乱数」 最小値「0」、最大値「RAND_MAX」の整数 「RAND_MAX」がいくつなのかは処理系に依存 printf(”%ld\n”,(long)RAND_MAX);で調べられる 「rand()」関数を使うには「#include <stdlib.h>」が 必要 プログラム実行毎に、異なる乱数の列を発生さ せたいときには、「srand(s)」関数を実行する 「srand(s)」関数と関数の系列 「s」の値(整数型、seedと呼ぶ)が異なると、乱数列 が異なる→例題ex10-4.c #include <stdio.h> #include <stdlib.h> int main(void) { int s,i,rn; srand(0); printf("seed=0\n"); /* seedが0 */ for(i=0; i<10; i++){ rn=rand(); printf("%d\n",rn); } printf("\n"); srand(1); printf("seed=1\n"); /* seedが1 */ for(i=0; i<10; i++){ rn=rand(); printf("%d\n",rn); } printf("seed sを入力: "); scanf("%d",&s); srand(s); printf("\n"); printf("seed=%d\n",s); for(i=0; i<10; i++){ rn=rand(); printf("%d\n",rn); } return 0; } テクニック srand((unsigned int)time(NULL)); とすると手で入力しなくてよい (#include <time.h>が必要) 範囲の決まった乱数の生成 「rand()」は0~RAND_MAXの範囲の乱数を生成 0~9の範囲の乱数を生成するには? 「剰余%」を利用! #include <stdio.h> #include <stdlib.h> #include <time.h> int main(void) { int i,r; srand((unsigned int)time(NULL)); for(i=0; i<10; i++){ r=rand()%10; /* 0~9の間の乱数、10で割ったあまりは0~9の範囲 */ printf(”%d\n”,r); } return 0; } 例題10-5ランダムなモンスター出現:dq2-1b.c (50%の確率で、メタルスライムかキラーマジンガーが出現) #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <time.h> printf("%s%s",quest1,yesno);/*旅?*/ scanf("%d",&a); if(a==1){ sleep(2); srand((unsigned int)time(NULL)); m=rand()%2; if(m==0){ printf("%s%s%s%s",name_m1,event1,quest2,yesno);/*M出現*/ } else{ printf("%s%s%s%s",name_m2,event1,quest2,yesno);/*M出現*/ } scanf("%d",&a); if(a==1){ /* メタルと戦う */ if(m==0){ battle1(name,name_m1); } else{ battle1(name,name_m2); } } else{ /* メタルと戦わない */ printf("%s",event2); sleep(2); printf(”%s%s",name,event3); sleep(2); } } else{ printf(”%s%s",name,event3); sleep(2); } printf("%s%s%s%s",king1,name,king2,king4); 17 return 0; int intromusic(void); int battle1(char name[], char name_monster[]); int main(void) { char name[20]; char king1[]="「王様」ゆうしゃ "; char king2[]=" よ "; char king3[]="りゅうおうを たおすのじゃ\n"; char king4[]="しんでしまうとはなさけない\n"; char quest1[]="たびにでる?\n"; char quest2[]="たたかう?\n"; char quest3[]="右へいく?\n"; char name_m1[]="メタルスライム"; char name_m2[]="キラーマジンガー"; char event1[]="があらわれた\n"; char event2[]="そのあと なにもであいませんでした\n\n"; char event3[]=”はへいぼんないっしょうをおえ、なくなりました\n\n"; char yesno[]="1. はい 2. いいえ\n"; int i,a,m; intromusic(); printf("名前を入れてください: "); scanf("%s",name); printf("\n\n"); printf("%s%s%s%s",king1,name,king2,king3); } 課題10-6: 丁半ゲーム(お金をかけてはいけません) サイコロを2個ふり、目の合計が偶数なら「丁(ちょう)」奇数な ら「半(はん)」とする。丁か半かを予測するゲームを行うとき、 2個のサイコロの代わりとなるプログラムを作成せよ。 ( ex10-6.c ) $ ./ex10-6.exe サイコロの目は3と2です 3-2の半です 課題 10-7 0から9までの乱数をN個発生させ,それぞれの数字が出た回数およ び確率を出力するプログラムを作成せよ。 とくにN=100と10000 の場合について, 確率のバラツキはどちらが小さいか確認せよ。 ( ex10-7.c) 18 モンテ・カルロ法 特別課題 10-8 乱数を利用して,円周率を計算せよ. なお,下の図を参 考にせよ. 使う乱数の数は10000, 1000000, 100000000と変え, それらの結果を比較せよ. ( ex10-8) この部分の 面積はπ/4 [注] 0と1の間の実数の乱数を得るには 例えば x=(double) rand()/RAND_MAX; とするとよい. 19 ドラクエもどき3 特別課題 10-9 dq2-1.c, dq2-2.cを改造し、メタルスライムに勝ったり負け たりするゲームを作成せよ. 20 実習結果のレポート • 2つのソースファイル「ex10-6.c」、「ex10-7.c」を 添付ファイルにしてメールを送ってください。 • 宛先: [email protected] • 件名:コンピューター基礎実験10 • 本文:感想および一言 21
© Copyright 2024 ExpyDoc