RAND(3)

名前
rand, srand - 乱数を生成する関数

書式
#include <stdlib.h>

int rand(void);

int rand_r(unsigned int *seedp);

void srand(unsigned int seed);

glibc 向けの機能検査マクロの要件 (feature_test_macros(7) 参照):

rand_r(): _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE

説明
rand() 関数は 0 以上 RAND_MAX 以下 (数学的に書くと [0, RAND_MAX]) の範囲の疑似乱数整数を返す。

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() は 0 以上 RAND_MAX 以下の数を返す。 関数 srand() は値を返さない。

準拠
関数 rand() と srand() は SVr4, 4.3BSD, C89, C99, POSIX.1-2001 に準拠している。 関数 rand_r() は POSIX.1-2001 に由来する。 POSIX.1-2008 は、 rand_r() を廃止予定としている。

注意
rand() と srand() の Linux C Library 版は、 random(3) と srandom(3) の両関数と同じ乱数生成 アルゴリズムを使用している。そのため、下位のビットは上位のビットと 同じくらいにランダムである。 しかし、旧版の rand() の実装や、他のシステムの現在の実装では、下位のビットが上位のビットほど ランダムになっていない。移植性を高める場合でも、精度の高い乱数が必要な アプリケーションではこの関数は使用してはいけない (代わりに random(3) を使うこと)。

例
POSIX 1003.1-2003 では、 rand() と srand() の実装例として以下を挙げている。これは、異なる２つのマシンで同じ乱数系列が 必要な場合には便利であろう。

static unsigned long next = 1;
/* RAND_MAX を 32767 と仮定 */
int myrand(void) {
    next = next * 1103515245 + 12345;
    return((unsigned)(next/65536) % 32768);
}
void mysrand(unsigned seed) {
    next = seed;
}

以下のプログラムを使うと、特定の乱数の種が与えられた場合に rand() が生成する疑似乱数系列を表示することができる。
#include <stdlib.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
    int j, 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 (j = 0; j < nloops; j++) {
        r =  rand();
        printf("%d\n", r);
    }
    exit(EXIT_SUCCESS);
}

関連項目
drand48(3), random(3)

この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.54 の一部 である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。