#include <stdlib.h> int rand(void); int rand_r(unsigned int *seedp); void srand(unsigned int seed);
glibc 向けの機能検査マクロの要件 (feature_test_macros(7) 参照):
rand_r():
srand() 関数は、 rand() 関数で作られる疑似乱数整数系列の新しい種として、 その引数の値を使用する。 これらの関数を使用して作られた疑似乱数系列は、 同じ値を引数として srand() を呼ぶことで、 再現することが可能である。
種の値が与えられない場合には、 rand() 関数は 自動的に 1 を種とする。
rand() 関数は再入可能 (reentrant) ではない。この関数には隠し状態があり、呼び出される度にこの隠し状態が変更されるからである。ちょうどこの隠し状態が次の呼び出し時の乱数の種として使われるようなものである。実際にはもう少し複雑かもしれないが。スレッドを使用するアプリケーションで再現可能な動作をさせたい場合には、この状態を明示的に指定できなければならない。これを行うには、再入可能な rand_r() 関数を使用する。
rand() と同様、 rand_r() は [0, RAND_MAX] の範囲の疑似乱数整数を返す。 seedp 引数は、rand_r() の呼び出し間で状態を保持するために使用される unsigned int へのポインターである。 seedp が指す整数に同じ初期値を rand_r() を呼び出し、 呼び出し間でその値が変更されなければ、同じ疑似乱数系列が得られる。
rand_r() の seedp 引数が指す値により提供される状態は非常に小さな空間 なので、この関数は弱い疑似乱数生成器になってしまう。 代わりに drand48_r(3) を使ってみるとよい。
インターフェース | 属性 | 値 |
rand(), rand_r(), srand() | Thread safety | MT-Safe |
static unsigned long next = 1;
/* RAND_MAX を 32767 と仮定 */
int myrand(void) {
next = next * 1103515245 + 12345;
return((unsigned)(next/65536) % 32768);
}
void mysrand(unsigned int seed) {
next = seed;
}
以下のプログラムを使うと、特定の乱数の種が与えられた場合に rand() が生成する疑似乱数系列を表示することができる。
#include <stdlib.h> #include <stdio.h>
int
main(int argc, char *argv[])
{
int r, nloops;
unsigned int seed;
if (argc != 3) {
fprintf(stderr, "Usage: %s <seed> <nloops>\n", argv[0]);
exit(EXIT_FAILURE);
}
seed = atoi(argv[1]);
nloops = atoi(argv[2]);
srand(seed);
for (int j = 0; j < nloops; j++) {
r = rand();
printf("%d\n", r);
}