今回は、「C言語/乱数を発生させる方法」についての説明です。
1.初めに
これまで使い方を説明してきた関数は、「stdio.h(スタンダードIO.h)」のライブラリを読み出すことで使用できる基本的な関数でした。
ここからは別のライブラリも読み出して、他にどんなことができるのかを確認していこうと思います。
今回は、乱数の作り方について説明していきます。
乱数とは、規則性のないバラバラな数値を発生させるための仕組みのことです。
ランダムな数値を用意することって結構あるので、そこそこ重要な内容となります。
2.今回使用するヘッダファイル
今回新たに登場するヘッダファイルは、「stdlib.h(スタンダードライブラリ.h)」と「time.h」です。
stdlib.h
「stdlib.h」は、その名の通り標準的(スタンダード)なライブラリです。
「stdio.h」とはまた別の関数やマクロなどが定義されています。
今回乱数を発生させるために使用するrand関数やsrand関数はこのライブラリを読み出すことで使用できるようになります。
後程使用例の説明をしますので、動作確認した後はわざと「stdlib.h」をコメントアウトさせてみると、どの関数が「stdlib.h」のおかげで使用できるようになっているのかの確認ができますので、試してみると覚えが良くなるかと思います。
time.h
「time.h」を読み出すと、time関数というものを使えるようになります。
その名の通り時間を取得するための関数です。
1970年1月1日からの経過秒数が取得できます。
Excelでも似たような数え方しますよね、確か。
今回は乱数を発生させるために常に変化する何かしらの値が欲しかったから使用しただけなので、詳しい使い方はまた別途まとめる…と思います。
3.乱数を発生させる方法
では、早速乱数を発生させるプログラムを見ていきましょう。
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void main() {
int a , b;
srand((unsigned)time(NULL));
a = rand() % 10 + 1;
b = rand() % 10 + 1;
printf(“a = %d , b = %d\n”, a, b);
printf(“a + b = %d”, a + b);
}
順番に見ていきますね。
まず、1~3行目でヘッダファイルが「stdio.h」・「stdlib.h」・「time.h」の3種類読み出されています。
先程述べた通り、乱数を発生させるための関数を取り扱うためにこの3種類が必要になるというだけの話です。
そして、7行目で初出のsrand関数が出てきます。
この関数は、簡単に言えば乱数を初期化するための関数です。
後で詳しく説明しますが、今は『こう入力することで乱数を発生させる下地ができてるんだなー』と思ってください。
実際、乱数を発生させる場合はtime関数を使って【srand((unsigned)time(NULL));】と記述するのがセオリーとなっていて、色んな場面でこの記述を使用しています。
8行目と9行目ではrand関数が登場します。
rand関数は、0から決められた最大値までの間の数をランダムに発生させる関数です。
なので、【rand() % 10 + 1】というのは、「乱数を10で割った余りに1を足した数値」に当たります。
【%】って割り算した時の余りを表していますからね。
10で割ると余りは0~9の何れかの値になりますよね?
そこに+1されているので、この場合は1~10という数値がランダムで選択されるようになります。
【rand() % 20】なら0~19、【rand() % 100】なら0~99という具合に、ここの数値を調整すれば乱数をどの範囲で発生させるのか自由に選択できるんです。
後は、printfで整数aと整数bの足し算の結果を表示しているだけです。
aもbも1~10の乱数なので、実行するごとに選ばれる数値が変化し、実行結果も変わってきます。
これが乱数の作り方です。
4.乱数の発生原理について
途中で飛ばしたsrand関数の補足説明です。
srand関数では、乱数を発生させる種を選んでいます。
チューリップの種があればチューリップが咲きますし、パンジーの種があればパンジーが咲きます。
そして、同じチューリップの種だとしても、種それぞれによってどんなチューリップが咲くのかはバラバラになります。
色・耐性・成長率など、何かしらが異なったチューリップが咲くのは当たり前ですよね?
では、ありえない話ですが、全く同じ種を全く同じ育て方をしたとしたら、どうなるでしょうか?
そんなことありえないから推測しかできませんが、普通に考えたら全く同じチューリップが咲くはずですよね?
この関係が、乱数の生成にも当て嵌まるのです。
乱数にも乱数を生成するための種が存在し、種が違っているからこそ別の規則・パターンで乱数が発生するのです。
そのパターンを決めているのがsrand関数という認識になります。
なので、本当にランダムな数を発生させているのではなく、疑似的な乱数を作っているのがsrand関数だと言えます。
このことから、srand関数で発生させる乱数は疑似乱数と呼ばれます。
srand関数は、【srand()】の括弧内に入る数値によってどんな乱数が作られていくのかが変化します。
逆に言うと、【srand(0)】のようにすると0番の種で固定されるので、同じパターンでしか乱数が生成されなくなります。
試しに、以下のようにプログラムを書き換えてみます。
7行目を【srand(0);】に変えただけです。
この状態でプログラムを実行すると、以下のようになりました。
a=9、b=10になりましたね。
以降、何度プログラムを実施しても、この結果が変わらなくなります。
これがsrand関数を固定することによる弊害です。
その為、乱数を発生させたいのならsrand関数の中身はランダムな値になるのが望ましいのです。
そうしないと、乱数調整しているのと同じで、全く同じ規則に則った値しか入手できなくなりますからね。
上記の理由から、1970年1月1日からの経過秒数を取得するtime関数を種の選択に使用しているというわけです。
毎秒変化していくなら、その時々で選ばれる変数の種もバラバラになるのです。
以上、「C言語/乱数を発生させる方法」についての説明でした。