話の発端は、StackOverflowの、この質問にあった。
StackOverflow 日本語版 - c言語での乱数生成
質問に対する回答は、きわめて単純で、rand()
関数を、取得したい乱数の個数分、呼んでやりましょうというもの。
いちおう、XcodeのCommand Line Toolで、サンプルコードを作って、それを実行してみて、ちゃんと意図したとおりの結果になることを確認する。が、ここで奇妙なことに気づく。
何度実行しても、初項が4になる。
試しに、こんなC言語のコードを書いて、Xcodeで実行してみる。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, const char * argv[]) {
unsigned int i;
unsigned int seed = (unsigned int)time(NULL);
for (i = 0; i < 100; i++) {
srand(seed + i);
printf("%d, ", rand() % 7);
}
putchar('\n');
return 0;
}
結果はこちら:
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2015年7月4日時点では4の繰り返しになりましたが、現時点(2015年7月6日)では2の繰り返しになります。値が変わったのは、乱数の種にtime()
関数を使っているからでしょう。
7の剰余を使うと、同じ値の繰り返しになりますが、それ以外の剰余、たとえば3だと、「2, 1, 0, 2, 1, 0……」と循環数になります。
これはひとめで、まずいと思う。実践的には、srand()
関数をなんども呼ぶことはないだろうが、毎回プログラムを実行すると、つねに初項がおなじというのは、きっと不都合な影響を出すに違いありません。たとえば、シューティングゲームのプログラムで、rand()
関数を使って、標的を出現させたとしたら、ゲームスタートで、いつも同じ標的が、おなじ場所から現れる、ってことになる。
言い遅れましたが、実行環境は、MacBook Pro、OS X 10.10.4 Yosemite、Xcode 6.4、Clangのバージョンは、Apple LLVM version 6.1.0 (clang-602.0.53)。
同様のプログラムを、iOS 8.4のiPadで動かしても、おなじ結果になります。まあ、それはそうでしょうね。
Mac、iOS、Clang以外の環境だと、どうなるんだろうか?ざんねんながらApple製以外のコンピュータがないので、C言語をウェブ上で実行してくれるサイトで、実験してみました。
前出のコードを上の2箇所で実行したら、ぱっと見、規則性が認められない結果が得られました。
なにが悪いんでしょうか?Clang、それとも、Appleが用意したC言語の標準ライブラリ?
どなたか、C言語の疑似乱数アルゴリズムに詳しい方がいらっしゃいましたら、なんでもいいんで、情報を共有してもらえたらありがたいです。