プログラミング実習II (2025) 課題

[T12] 第10章 ファイルと乱数


(T12_0) 準備として10.1節を読むこと.


(T12_1) ファイルからデータを読み込んで計算を行うプログラムを作成する.

79
45
21
98
93
41
68
41
11
32
0

(T12_2) 教科書 p. 354〜356,および副読本「キックオフ C言語」の p. 196(電子版は課題ページのリンク参照)に必ず目を通した上で,コマンドラインから引数を与える方法を以下に従って理解せよ(この後の問題のため,ファイル名を表す文字列を受け取ることを想定する).

#include <stdio.h>
#include <stdlib.h>

int main( int argc, char *argv[] )
{
    if( argc != 2 ){
        printf("使い方: %s filename \n", argv[0]);
        exit(EXIT_FAILURE);
    }

    return 0;
}

(T12_3) [リスト 10.3] を参考にして,入力するファイルを実行時に指定できるように課題 (T12_1) のプログラムを書き換えよ.


(T12_4) [リスト 10.4]を参考にして,データの終わりを 0 で示さなくても終了を判定できるように前問のプログラムを書き換えよ. indata.txt は上の問題で用いたものと同一する.プログラムを実行し (今度は末尾の 0 がデータとして認識される), 平均値 48.09,最大値 98,最小値 0 となることを確かめよ.


(T12_5) 乱数とはランダムに(不規則的に)発生する数を指す. 真の意味での乱数を得る手法として,ある物理的現象を観察するものが知られている. 一方,コンピュータでプログラムに従って行われる計算はあくまで 確定的であるため,真の意味での乱数を生成することは困難である. このため,コンピュータでランダムな数を必要とする場合は,確定的 な計算により乱数のように見える擬似乱数と呼ばれるものを生成する.擬似乱数はシミュレーションを行う場合などに有用である.
下記の<解説>を読み,(練習1)から(練習3)の説明にしたがってプログラムすることで乱数について理解したのち,[設問]に解答せよ.プログラムは,[設問]で作成したものを提出せよ.

[乱数についての理解のための練習]
(練習1) (program1)のプログラムは0 以上 RAND_MAX 以下の乱数を10個生成するプログラムである.このプログラムを何回か実行し,それらの結果を比較せよ.
(練習2) rand を使い,サイコロを10回振って出た目を表示するプログラムを作成せよ.
また,作成したプログラムを 2 度実行しこれらの結果を比較せよ.
(練習3) (program2)のプログラムは乱数を10個生成するプログラムである.このプログラムを何回か実行し,結果を(練習1)の結果と比較せよ.

[設問]
srand を使い,サイコロを10回振ってランダムに出た目を表示するプログラムを作成せよ.
また,作成したプログラムを何度か実行し考察せよ.(ただし,考察はこの設問だけでなく練習1から3についても記すこと.)

--<解説>----------------------------------------------------------------

C言語には、疑似乱数を作るrand関が用意されている.
なお、rand関数を使うには <stdlib.h> を #include する必要がある.

変数 = rand();

rand関数には、特にパラメータなどを渡す必要はなく、そのまま使うだけでランダムな値を計算する.

(練習1)次のプログラムを実行して、乱数を10回計算せよ.何回か繰り返し実行せよ.

(program1)

#include <stdio.h>
#include <stdlib.h>
int main(void) { for ( int i = 0; i < 10; i++ ) { printf("%d\n", rand() ); }
return 0; }

乱数の範囲を限定するには
[手順1] 0から任意の値までの乱数を求める
rand関数から返ってくる値を,任意の値+1で割った余りを求めると,0から任意の値までの整数になる.

rnd = rand() % (6 + 1);

※7で割った場合の余りは0,1,2,3,4,5,6のいずれかになる.
[手順2] 任意の範囲内で乱数を求める
例えば下限が1,上限が6の範囲で乱数を発生させるには,0から5(上限−下限)の乱数に1(下限)を加算すればよい.

rnd = 1 + rand() % (6 - 1 + 1);

※0から5の範囲で発生させた乱数に1を足すことにより,1から6の範囲になる .

乱数の値 = 下限の値 + rand() % (上限の値 − 下限の値 + 1);

(練習2)サイコロを10回振って出た目を表示するプログラムを作成し,2度試行して考察せよ.

毎回異なる乱数にする

(練習1)の使用例のプログラムは,実は何回実行しても同じ値の乱数が発生してしまう.これは、rand関数を呼び出す際、乱数列の開始点を指定していないため,一番最初から表示してしまうためである.
乱数列の開始点を指定するには、「srand関数」を利用する。

srand(元の数);

ただし、srand関数を使って別の数値を入れたとしても、実行される時に元の数が同じであれば同じ乱数になる.
これを解決する方法に,現在時刻を入れる方法がある.
秒単位の現在時刻をsrand関数に入れれば、毎回異なる元の数を乱数に使える。

現在時刻を得る関数はtime関数で <time.h> を #include する必要がある.
srand関数とtime関数を次のように使えば,毎回異なる乱数を計算できる.

srand((unsigned int)time(NULL));

unsigned int という型にキャストしているが,これは符号なしの整数値である.
この処理はプログラムを開始するときに1回行えだけでよい.

(練習3)次の乱数を10回計算するプログラムを何回か繰り返し実行し,(練習1)のプログラムと比較せよ.

(program2)

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) { srand((unsigned int)time(NULL));
for ( int i = 0; i < 10; i++ ) { printf("%d\n", rand() ); }
return 0; }