rand
randは、引き続く呼び出しが擬似乱数列を返すような手続きに付けられる名前である。以下主に標準Cライブラリのそれについて説明する。
目次 |
[編集] 概要
(以下、基本的に C90(JIS X 3010-1993、§7.10.2)に従う)stdlib.hで宣言されている、0以上かつ定数RAND_MAX以下(数学で使う「以上」「以下」であり両端を含む)の整数値を返す関数である。ランド、ランダムと呼ばれている。標準ではマルチスレッドについて触れられておらず、POSIXではスレッドセーフに実装することを要求していない[1]。
また、標準は、randが生成すべき乱数列の品質など、乱数列の乱数性については何も言及していない。
[編集] 初期化
randの引き続く呼び出しが返す乱数列はsrandで初期化される。srandを呼び出さずにrandを使った場合は、最初に引数を1としてsrandを呼び出した場合と同じように動作しなければならない(§7.10.2.2)。乱数列の初期化はBASICでRANDOMIZEというコマンドであるためランダマイズと呼ばれることもある。
実行ごとに異なる乱数列を生成するために、簡便な手法としては時刻などが使われる。暗号などの応用では外部から予測が不可能(ないし十分に困難)な方法を使わなければならない。逆に、シミュレーションを再現するためなどでは、同じ数を使用して同じ乱数列を返すようにする。
srandは乱数列を初期化するものであるから、randを使用する度にsrandを呼んだりするのは、誤った用法である。
[編集] randの問題点
古いrandの実装が生成する乱数列は、問題があるものがほとんどだったことが指摘されている[2]。現代のライブラリでは問題があるものは少なくなっているが、標準の規格書で示された実装例があまり良いものではなかったことや、古いライブラリと同じコードが使われ続けているものもまだあることから、注意を要する。
前述の規格書に示された例をはじめ、randの実装に線形合同法が使われていることがあるので、線形合同法の欠点に注意する必要がある。詳細は線形合同法#欠点を参照すること。
ライブラリには標準外でより高品質のrandom、rand48等が用意されていることがある。また、メルセンヌ・ツイスタ等のより良い生成法を検討すべきである。
[編集] 形式
#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とする方法も広く知られているが、線形合同法などの下位ビットの乱数としての品質が低い生成法に備えるため上記のコード例のような上位にあるビットを利用するコードが推奨されている。
[編集] 関連項目
[編集] 参考文献
- ^ http://pubs.opengroup.org/onlinepubs/009695399/functions/rand.html
- ^ Random number generators: good ones are hard to find
[編集] 外部リンク
- Boost Random Number Library - 様々な乱数アルゴリズムを使うことが出来るBoostライブラリ
- Boost Random Number Library (cppll) - cppllによる上記の翻訳