rand

出典: フリー百科事典『ウィキペディア(Wikipedia)』
Jump to navigation Jump to search

randは、引き続く呼び出しが擬似乱数列を返すような関数に付けられる名前である。ランドランダムと呼ばれている。以下主に標準Cライブラリのそれについて説明する。

概要[編集]

(以下、基本的に C99に従う)stdlib.hで宣言されている、0以上かつ定数RAND_MAX以下(数学で使う「以上」「以下」であり両端を含む)の整数値を返す関数である。標準ではマルチスレッドについて触れられておらず、POSIXではスレッドセーフに実装することを要求していない[1]

また、標準は、randが生成すべき乱数列の品質など、乱数列の乱数性については何も言及していない。

初期化[編集]

randの引き続く呼び出しが返す乱数列はsrandで初期化される。srandを呼び出さずにrandを使った場合は、最初に引数を1としてsrandを呼び出した場合と同じように動作しなければならない。srandに相当するステートメントが、一部のBASICでRANDOMIZEという名前であったためランダマイズと呼ばれることもあるが、「種子英語版」を与えているだけで、何かをランダムにしているわけではない。

実行ごとに異なる乱数列を生成するために、簡便な手法としては時刻などが使われる。暗号などの応用では外部から予測が不可能(ないし十分に困難)な方法を使わなければならない。逆に、シミュレーションを再現するためなどでは、同じ数を使用して同じ乱数列を返すようにする。

srandは乱数に種子を与え初期化するものであるから、randを使用する度にsrandを呼んだりするのは、誤った用法である。

randの問題点[編集]

古いrandの実装が生成する乱数列は、問題があるものがほとんどだったことが指摘されている[2]。現代のライブラリでは問題があるものは少なくなっているが[要出典]、標準の規格書で示された実装例があまり良いものではなかったことや、古いライブラリと同じコードが使われ続けているものもまだあることから、注意を要する。

前述の規格書に示された例をはじめ、randの実装に線形合同法が使われていることがあるので、線形合同法の欠点に注意する必要がある。詳細は線形合同法#短所を参照すること。

ライブラリには標準外でより高品質のrandom、rand48等が用意されていることがある。また、メルセンヌ・ツイスタ等のより良い生成法を検討すべきである。

srandとシードの問題点[編集]

srand()にtime()等で得た現在時刻(秒単位)を渡して初期化する方法はよく見かけるが、srandの実装によってはシード値が近いとrandによって生成される乱数も相関性の高い値が出力されるものがある。つまり下記例のような実装方法を採るプログラムを起動してから数秒後に同じプログラムを起動すると最初のうちは同じ乱数列を得る可能性が高い。これを回避するためにはtimeで得た値をハッシュ関数に通してからsrandに渡す、もしくはsrandを呼び出した後のrandは数十〜数百回読み飛ばすなどの対策が必要である。また言うまでもなく同じロジックを採用したプログラムが同一時刻に起動されるなどしてsrandが同一の値で初期化された場合は以降全く同じ乱数列を得ることになる。

形式[編集]

#include <stdlib.h>
int rand(void);
void srand(unsigned);

コード例[編集]

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
    int a;
    srand((unsigned int) time(0));
    a = (int)((rand() / ((double) RAND_MAX + 1.0)) * 10);
    printf("%d", a);
    return 0;
}

出力結果(例。0~9のいずれかの値が返る):

8

srandの際に現在時刻を使用しているが、これは実行ごとに異なる乱数列を生成するための、簡便なよく使われる手法である。暗号などの応用では外部から予測が困難な方法を使わなければならない。

特定の範囲で乱数を求めたいときにはa = rand() % 10とする方法も広く知られているが、線形合同法などの下位ビットの乱数としての品質が低い生成法に備えるため上記のコード例のように上位にあるビットを利用することが推奨されている[3]。とはいえ両コードともrandの質とは関係なく分布に偏りが発生する方法であり注意が必要である。

参考文献[編集]

外部リンク[編集]