C言語:乱数でサイコロの目が均等に出るか?

台風13号が近づいてきました。
自然を前にするとやはり人間ってちっぽけな存在だと思いますね。

ところで、乱数をご存じでしょうか?
例えばプログラムで1から6のサイコロの目を表現するのに乱数というものを使います。
C言語だとこんな感じで記述します。

/* サイコロの目(1~6)を乱数で表現する */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
	int sai;
	
	srand((unsigned)time(NULL));

	sai = rand() % 6 + 1;
	printf("コロコロッ! %d ", sai);
	
	return 0;
}

実行結果

コロコロッ! 5

C言語の場合は、rand()関数で整数の乱数を取り出せます。
1~6までの数値を取り出したいなら、rand()関数を6で割ったあまりに1を足します。
整数を6で割ると、あまりは0から5までとなるので1を足して1~6の範囲に変更しています。

実際にこのサイコロを10000回振ったとして、どの程度均等に1~6の目が出ているのか確認するプログラムを作ってみました。
1~6の目が何回出現したかを記憶するために配列saiを用意します。

int sai[6];

イメージとしては、配列の中身は、添え字毎に出た回数が保存されこんな風になる感じです。
sai[0]がサイコロの目の1に対応しています。sai[5]だとサイコロの6の目という意味です。

sai[0] 1735
sai[1] 1640
sai[2] 1624
sai[3] 1664
sai[4] 1704
sai[5] 1633

実際にプログラム化してみました。

/* 乱数でサイコロの目が均等に出るか?を確認するプログラム */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
	int x, i;
	int sai[6];
	
	/* 乱数系列を初期化 */
	srand((unsigned)time(NULL));

	/* 配列を0クリア */
	for(i=0; i<6; i++) sai[i] = 0;
	
	for(i=0; i<10000; i++){
		x = rand() % 6 + 1;	/* サイコロを振る */
		printf("%d ", x);
		sai[x-1] ++;			/* でた目を記憶 */
	}
	
	/* 10000回振ったあとの出た目の回数と割合を表示 */
	for(i=0; i<6; i++){
		printf("%dの目: %5d回 %5.1f%%\n", i+1, sai[i], (float)sai[i]/100 );
	}
	
	return 0;
}

実行結果

4 2 3 1 3 5 4 6 3 4 2 4 4 1 2 3 4 2 6 1 2 4 6 5 3 4 3 4 5 3 3 3 1 1 5 2 2 2 1 3 5 5 4 5 4 3 2 1 6 2 2 2 5 2 6 1 1 1 4 1 4 5 6 1 2 6 1 6 4 4 2 3 5 4 3 5 2 2 4 1 1 5 6 2 2 4 5 1 3 2 2 5 2 6 6 2 2 2 5 3 4 2 4 4 6 6 5 2 1 6 6 6 1 6 6 1 5 3 1 5 2 6 1 2 4 1 4 2 2 2 5 2 2 4 3 5 2 6 1 1 6 1 3 2 6 1 2 3 6 4 5 4 5 3 4 3 3 2 2 6 6 1 3 6 1 4 5 2 3 3 3 3 1 5 3 4 6 2 2 3 5 1 6 6 4 6 5 5 4 4 4 6 3 3 1 3 6 3 4 3 5 2 3 6 5 1 1 4 1 2 3 2 1 5 4 1 1 2 3 5 1 6 1 2 5 3 2 2 5 2 5 4 4 4 2 2 4 2 3 3 1 2 6 4 5 5 3 3 3 4 2 2 2 1 1 6 1 2 1 1 3 1 2 3 4 3 2 2 3 5 1 4 4 2 3 4 1 2 5 4 5 3 4 6 5 2 2 4 2 1 4 6 4 3 3 2 3 2 3 1 3 6 6 5 4 4 2 2 3 1 4 6 2 3 6 2 4 6 5 5 6 3 5 1 3 4 1 1 1 6 4 3 2 4 4 3 5 1 1 4 5 1 5 6 6 2 6 3 3 2 3 6 6 3 1 6 5 3 1 5 2 6 6 3 3 4 5 4 1 5 1 2 1 3 1 2 2 1 6 3 6 6 5 5 2 4 6 3 5 6 3 4 5 3 1 5 3 5 2 5 2 3 2 1 5 2 6 5 3 6 5 1 1 3 4 1 1 6 2 6 5 2 1 6 3 6 3 5 2 2 4 6 2 6 2 1 3 5 4 2
1の目: 1709回 17.1%
2の目: 1740回 17.4%
3の目: 1636回 16.4%
4の目: 1667回 16.7%
5の目: 1677回 16.8%
6の目: 1571回 15.7%

だいたいどの目も16%前後で平均しているようです。
均等ですね。

ポイントは、配列をインクリメントしている部分です。

sai[x-1] ++; /* でた目を記憶 */

配列はこんな感じで使うと使い道があります。

ちなみにわたしは最初に「乱数」といいましたが、実際は「疑似乱数」です。
乱数を真似たもの、という感じです。
乱数表は実際には人間が作り出したものなので、上記のプログラムで

/* 乱数系列を初期化 */
srand((unsigned)time(NULL));

の部分を消して実行すると毎回同じ数値が出現することになります。
コンピュータ内部の乱数表を参照しているからです。(乱数表という沢山のバラバラの数値が書き込まれた一枚の紙きれがあると考えてください)
上記のsrand関数で行っているのは、乱数表に適当な数値を掛け合わせて違う数を取り出しているように見せているだけです。

本物の乱数は、今接近している台風13号の進路かもしれませんね。
コンピュータも自然には勝てません。

ではまた。

コメントを残す

メールアドレスが公開されることはありません。