RANDOM(3)

名称
random, srandom, srandomdev, initstate, setstate - 優れた乱数ジェネレータ、およびジェネレータを変更するルーチン

ライブラリ
libc

書式
#include <stdlib.h> long random(void) void srandom(unsigned long seed) void srandomdev(void) char * initstate(unsigned long seed, char *state, long n) char * setstate(char *state)

解説
random() 関数は、非線形加法フィードバック乱数ジェネレータを使用し、 デフォルトでサイズが 31 の、ロング整数のテーブルを採用して、0 から (2**31)-1 までの範囲で連続した疑似乱数を戻します。 この乱数ジェネレータの周期は非常に大きく、約 16*((2**31)-1) です。

random() 関数と srandom() 関数の呼び出し手順と初期化プロパティは、 rand(3) 関数と srand(3) 関数のものと (だいたい) 同じです。 違いは、 rand(3) が作成するランダムシーケンスがかなり劣ったものであることです。 実際、rand が作成する下位の多くのビットは、循環パターンになります。 random() が作成するビットはすべて使用できます。 たとえば ‘random()&01’ では、ランダムなバイナリ値が作成されます。

rand(3) と同じように、 random() は数値のシーケンスをデフォルトで作成します。 このシーケンスは、種を ‘1’ にして srandom() を呼び出すと再作成できます。

srandomdev() ルーチンは、暗号化での使用に適した乱数を戻す urandom(4) 乱数デバイスを使用し、状態配列を初期化します。 この初期化プロシージャは、どのような値で srandom() を呼び出しても再作成できない状態を作成することに注意してください。 状態バッファ内の連続する項は、固定の種の場合に適用される LC アルゴリズムでは導出できないからです。

initstate() ルーチンは、引数として渡された状態配列を、後の使用のために初期化します。 initstate() は、状態配列のサイズ (バイト単位) を使用し、 乱数ジェネレータの複雑さを決定します。 状態を大きくすると、乱数の質は上がります。 (現在のところ、状態情報の量に「最適」な値は、8 バイト、32 バイト、 64 バイト、128 バイト、256 バイトです。 その他の値は、最も近い値に切り下げられます。 8 バイトより小さい値を使用するとエラーとなります。) 初期化の種 (乱数シーケンスの開始点を指定し、同じ点から再開できる) も引数です。 initstate() 関数は、以前の状態情報配列へのポインタを戻します。

状態を初期化したら、 setstate() ルーチンで状態を素早く切り替えられます。 setstate() 関数は、以前の状態配列へのポインタを戻します。 引数である状態配列は、次に initstate() か setstate() を呼び出すまで、さらに乱数を作成するのに使用されます。

状態配列を初期化したら、 initstate() を (目的の種、状態配列、サイズで) 呼び出すか、 もしくは (状態配列を指定した) setstate() と (目的の種を指定した) srandom() の両方を呼び出すことで、異なる点から再開できます。 setstate() と srandom() の両方を呼び出すと、状態配列のサイズを初期化した後で記憶する必要がない という長所が得られます。

状態情報を 256 バイトにすると、乱数ジェネレータの周期は 2**69 より大きくなります。 この周期では、ほとんどの目的に十分に対応できます。

作者
Earl T. Cohen

診断
状態情報を 8 バイトより小さくして initstate() を呼び出したり、状態情報が歪められたことを setstate() が検出したりすると、エラーメッセージが標準エラー出力に出力されます。

関連項目
rand(3), srand(3), urandom(4)

歴史
この関数は、 4.2BSD で登場しました。

バグ
処理速度は、 rand(3) の約 2/3 です。

古い実装では初期化のプロセスが非常に弱く、 種を用いてもランダムシーケンスはあまり変わりませんでした。 現在のシステムは、より良い疑似乱数ジェネレータを 初期状態の算出に採用しています。