C言語では、「stdlib.h」で宣言される関数rand()を利用することにより、乱数を生成することが可能です。rand()は0以上RAND_MAX(stdlib.hにおいて定義されている定数)以下の乱数を返す関数で、たとえば次のようにして用います。
#include <stdio.h>
#include <stdlib.h>
int main(void){
printf("%d\n", rand()); //0以上RAND_MAX以下の乱数を生成
printf("%d\n", rand()%100); //0以上100未満の乱数を生成
printf("%d\n", (double)rand()/RAND_MAX); //0以上1以下の実数を生成
return 0;
}
このプログラムを実行すると、確かにランダムな数が生成されているように見えますが、実は同じプログラムを何度実行しても同じ値が表示されます。どうやら、真にランダムであるとは言えなさそうです。(確認してみください) この理由は、得られている乱数が実際には真の乱数ではなく確定的な計算によって得られている擬似乱数であることに由来します。たとえば線形合同法と呼ばれる擬似乱数列の生成方法では、漸化式Xn+1 = (AXn + B) (mod M)によって乱数列を生成します。(A, B, Mはあらかじめ定数として与えられているとします) ここでnはrand()関数を読んだ回数なので、rand()を呼ぶたびに異なった値が得られますが、初項X0が同じであれば乱数列としては毎回同じ数列になってしまうことがわかります。これが「何度実行しても同じ値が表示されてしまう」理由です。実用上はプログラム実行の際に異なる乱数列を得たいわけですが、その場合はプログラムを実行するたびに異なるX0を与えれば良い事になります。ここで、初項X0を決定する値をseed値と呼びます。
なお、線形合同法には様々な問題点があることが指摘されており、より高性能な擬似乱数列が必要な時には、メルセンヌツイスター法などの高度な乱数生成方法が用いられます。(ただし、seed値が必要な事には変わりはありません。乱数の詳細は、理学部情報科学科の主催講義である2A「情報数学」や3A「連続系アルゴリズム」で説明されます。)
seed値を変更するためにはsrand関数を利用します。
#include <stdio.h>
#include <stdlib.h>
int main(void){
srand(100);
printf("%d\n", rand()); //0以上RAND_MAX以下の乱数を生成
printf("%d\n", rand()%100); //0以上100未満の乱数を生成
printf("%d\n", (double)rand()/RAND_MAX); //0以上1以下の実数を生成
return 0;
}
このプログラムを実行すると、先ほどのプログラムとは異なった乱数値が生成されることが確認できますが、やはり同じプログラムを何度実行しても同じ値が表示されます。これは、seed値をdefaultの値から変更したというだけで、プログラム実行ごとにseed値が変わるわけではないためです。 rand関数で実行のたびに異なった乱数列を得るためには、実行の際に異なった数をseed値に設定しなければりません。方法としては様々な方法がありますが、ここでは現在の時刻をseed値として与える方法を紹介します。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void){
srand((unsigned)time(NULL);
printf("%d\n", rand()); //0以上RAND_MAX以下の乱数を生成
printf("%d\n", rand()%100); //0以上100未満の乱数を生成
printf("%d\n", (double)rand()/RAND_MAX); //0以上1以下の実数を生成
return 0;
}
time関数はtime_t型で表現された現在の時刻を返却します(time.hをincludeする必要があります)。プログラムを実行するごとに時刻は変化するため、実行ごとに異なるseed値を設定していることになります。(実際に実行のたびに異なる乱数が生成されていることを確認しましょう。)