C言語でグラフィックス | ||
乱数について |
【乱数】
乱数とは、それぞれの数字が同じ確率で現れるように並べられた数字の列のことである。
例えば、整数1から10の範囲の乱数では、それぞれの数字が同じ確立で現れる。
C言語のプログラムでは、rand関数を使う。この関数は乱数を計算で求めており、各数字が正確に同じ確率で現れることはないので、擬似(ぎじ)乱数とも呼ばれる。このとき、ある値を元に乱数を計算し、2回目以降は前回の乱数値を元に計算するので、最初のある値(初期シード値という)が同じであれば、同じ乱数の列が現れる言語もある。
初期シード値を設定するため、srand関数が用意されている。time関数でシステムタイマー(コンピュータ内蔵の時計)から取り出した値を初期値として使用する。
◆サンプルプログラム 〔time1.c〕
time関数で得られる値を確認する。
#include <stdio.h> #include <stdlib.h> #include <time.h> int main(void) { time_t t, x; t = time(NULL); /* 現在時間の取得 */ printf("%ld秒\n", t); x = t / 60; printf("%ld分\n", x); x = t / 3600; printf("%ld時\n", x); x = t / 3600 / 24; printf("%ld日\n", x); x = t / 3600 / 24 / 365; printf("%ld年\n", x); printf("%ld年\n", 2005 - x); return 0; }
time_t time(time_t *tp); |
D:work>time1 1119169031秒 18652817分 310880時 12953日 35年 1970年 |
実行すると、現在の時刻が1970年1月1日午前0時0分0秒からの通算秒数で得られる。
現在時刻の取得(t = time(NULL);)の部分は次のように書くこともできる。
t = time(&t);
time(&t);
◆サンプルプログラム 〔rand1.c〕
乱数を20個表示する。
#include <stdio.h> #include <stdlib.h> #include <time.h> int main(void) { int n, rnd; srand(time(NULL)); /* 乱数の初期化 */ for(n = 0; n < 20; ++n){ rnd = rand(); /* 乱数の取得 */ printf("%d\n", rnd); /* 乱数の表示 */ } return 0; }
void srand(unsigned int 初期値); |
int rand(void); |
実行すると、20個の乱数が表示される。実行するごとに違う値が表示される。
◆サンプルプログラム 〔rand2.c〕
乱数値を1未満にして20個表示する。
#include <stdio.h> #include <stdlib.h> #include <time.h> int main(void) { int n; float rnd; srand(time(NULL)); /* 乱数の初期化 */ for(n = 0; n < 20; ++n){ rnd = (float)rand() / 32768.0; /* 1未満の乱数計算 */ printf("%f\n", rnd); } return 0; }
乱数値の最大32767(7FFF(16))+1で割って1未満の値に計算(変換)している。
◆サンプルプログラム 〔rand3.c〕
0から9までの10種類の乱数を発生させて、それぞれの値の発生回数を調べる。
#include <stdio.h> #include <stdlib.h> #include <time.h> #define MAX 10000 int main(void) { int n, d, ds[10]; float rnd; srand(time(NULL)); /* 乱数の初期化 */ for(n = 0; n < 10; ++n) /* 回数カウント用配列の初期化 */ ds[n] = 0; for(n = 0; n < MAX; ++n){ rnd = (float)rand() / 32768.0; /* 1未満の乱数計算 */ d = (int)(rnd * 10.0); /* 10未満の乱数計算 */ ++ds[d]; /* 回数カウント */ } for(n = 0; n < 10; ++n) printf("%d : %8d (%5.2f%%)\n", n, ds[n], (float)ds[n] / MAX * 100.0); return 0; }
D:\work>rand3 0 : 941 ( 9.41%) 1 : 929 ( 9.29%) 2 : 1005 (10.05%) 3 : 1025 (10.25%) 4 : 1007 (10.07%) 5 : 978 ( 9.78%) 6 : 1054 (10.54%) 7 : 1030 (10.30%) 8 : 1007 (10.07%) 9 : 1024 (10.24%) |
実行すると、それぞれの値はおよそ1000回(10%)発生している。このことからrand関数で得られる値は乱数になっていると考えても良いだろう。
実行するごとに結果は異なる。
◆サンプルプログラム 〔rand4.c〕
特定範囲の乱数を計算する関数を作成して、15から24までの10種類の乱数を発生させて、それぞれの値の発生回数を調べる。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX 10000
int xrand(int, int); /* 特定範囲の乱数発生関数 */
int main(void)
{
int n, ds[10];
srand(time(NULL));
for(n = 0; n < 10; ++n)
ds[n] = 0;
for(n = 0; n < MAX; ++n)
++ds[xrand(15, 24) - 15];
for(n = 0; n < 10; ++n)
printf("%d : %8d (%5.2f%%)\n", n + 15, ds[n], (float)ds[n] / MAX * 100.0);
return 0;
}
int xrand(int lower, int upper)
{
return (upper - lower + 1) * (float)rand() / 32768.0 + lower;
}
int xrand(int lower, int upper); |
ユーザ関数xrandを用意すれば、プログラムもすっきりとするし、便利である(かな?)。
もう一つ、1未満の乱数を発生するユーザ関数も用意すると便利かもしれない。次に関数だけを示しておく。
float frand(void) { return (float)rand() / 32768.0; }
▼課題1 〔rand5.c〕
乱数を使って100本の直線を黒色で描画するプログラムを作成せよ。
▼課題2 〔rand6.c〕
乱数を使っていろいろな色の100個の円・だ円を描画するプログラムを作成せよ。
Copyright © 2005 Hiroshi Masuda |