疑似乱数を使おう!

こんにちは、めのんです!

今日は疑似乱数の生成について解説します。
といっても大した内容ではありませんし、PHPとの共通点も多いので、PHPとCの相違点を中心に解説していければと思います。

標準の疑似乱数

まずは標準規格の疑似乱数から見ていきますね。

rand関数

Cでは疑似乱数の生成には「rand関数」を使います。
rand関数は「stdlib.h」ヘッダで次のように宣言されています。

int rand(void);

PHPにもrand関数はありますが、引数無しのrand関数と同じだと思っていいでしょう。
ただ、ご覧のように引数を受け取りませんので、PHPのrand関数のようにminとmaxを指定することができません。

もしminやmaxを指定したときのように使いたいなら、次のようにするといいでしょう。

int r = rand() % (max - min) + min

ところで、rand関数が返す最大値はRAND_MAXです。
PHPでは最大値にgetrandmax関数を使いますが、Cではマクロで定数値が定義されています。

srand関数

rand関数をそのまま使うと毎回同じ乱数列を生成してしまいます。
これだと問題があることが多いと思います。

毎回異なる乱数列を生成するには「srand関数」を使います。
srand関数はPHPにもありますが、PHPではsrand関数を呼び出さなくても自動的に毎回異なる乱数列を生成してくれるようになっています。
Cではそんなことはありませんので注意が必要です。

srand関数は「sdtlib.h」ヘッダで次のように宣言されています。

void srand(unsigned int seed);

PHPのsrand関数とは異なり、seedは省略できません。
普通は暦時間を求めるtime関数を使って、次のように使います。

srand((unsigned int)time(NULL));

もっと高性能な疑似乱数

PHPのrand関数はmt_rand関数と同じ疑似乱数を生成します。
これはメルセンヌツイスタというアルゴリズムを使うもので、ちょっと前までは最良の選択とされていました。

Cのrand関数も処理系によってはメルセンヌツイスタを使っていますが、基本的には線形合同法という簡易的なアルゴリズムを使っています。
標準規格では次のような実装例が挙げられています。

static unsigned long int next = 1;

int rand(void)  // RAND̲MAXを32767と仮定する。
{
  next = next * 1103515245 + 12345;
  return (unsigned int)(next/65536) % 32768;
}

void srand(unsigned int seed)
{
  next = seed;
} 

近年では、生成される乱数列はメルセンヌツイスタほどではないものの高速なXorshiftもよく使われています。
Wikipediaにも実装例があるので参考にしてみてください。

さらに最近ではXorshiftを改良したxoshiro / xoroshiroというアルゴリズムも登場しました。
これらのアルゴリズムもパブリックドメインで実装例が公開されていますので、ぜひご自身で確認してみてくださいね。


簡単ですが、今回の解説は以上になります。
次回はファイルの扱いについて解説したいと思います。
どうぞご期待ください!