[前へ]   [目次へ]   [次へ]

疑似乱数の生成(2)(C/C++)

今回は、 rand 関数が返す値の範囲と任意の範囲を取得する方法についてです。
前回のプログラムを何度も実行しているとわかるかと思いますが、 rand 関数はあまり大きな数を返しません。
また、取得できる値の範囲も指定できないので、そのままでは任意の範囲を取得できません。

まず、 rand 関数が返す値の範囲ですが、
0から RAND_MAX という定数値までの int 型の値を返します。
RAND_MAX は stdlib.h で定義されています。
この範囲はコンパイラによりますが、以下のようなコードで使用しているコンパイラの範囲がわかります。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
   printf(
"%d",RAND_MAX);
   
//終了待ち
   
getchar();
   
return 0;
実行例:
32767

この場合、 rand 関数が返す可能性のある値は 0〜32767 ということになります。

さて、今回のゲームでは0〜9の値が欲しいので、10以上の値が入ってきては困ります。
今回に関わらず、普通乱数というものは任意の範囲で取得したいものなので、
以下の式を使って範囲を指定します。

rand()%(最大値-最小値+1)+最小値

最大値は欲しい範囲の最大値、最小値は欲しい範囲の最小値です。
今回の0〜9という範囲に当てはめると、

rand()%(9-0+1)+0

で、0で加減算しても意味がないので、0を消して、定数項を計算すると、

rand()%10

となります。

ここで %って何? って声が聞こえてきそうなので解説します。
%(剰余)演算子(二項、算術、優先13、結合→)は、左辺値を右辺値で割った時の余りを返す演算子です。
整数型では 10/3 とすると3になり、小数点以下は切り捨てられてしまいます。
この演算子はこの時切り捨てられた余りを取得します。
つまり、 10%3 とすると10/3の余り、1が返されます。
また、この演算子の優先順位は除算と同じになっています。

ここでポイントなのは、余りというのは 右辺値より小さい値 しか出ないという点です。
例えば、11%3は余り2ですが、12%3になると割り切れるので余りは0になります。
これを利用すると、0から任意の範囲の値を生成することができます。
ただし、 RAND_MAX より大きな値にはならないので大きな範囲が必要な時は別の細工が必要です。

また、5〜7のような範囲が必要な時は、この剰余算の結果得られた値に最小値を加算することで生成できます。
これが、上記の

rand()%(最大値-最小値+1)+最小値

という式ができる理由です。
値を当てはめれば、

rand()%(7-5+1)+5

となり、定数項を計算すると

rand()%3+5

この時、 rand()%3 の方が優先順位が高いので rand()%8 とはなりませんのでご注意。
ここで、 rand()%3 の結果が0〜2になるので、それに5を加算すれば5〜7が完成します。

なお、 rand 関数が実行する計算式と上記の式は相性が悪いことがあるようです。
rand 関数内部の乱数生成式が生成する値にはある種のパターンが混じっていて、
それと剰余の右辺値のパターンがぶつかってしまうと異常に法則的になってしまう場合があるようです。

今のところ私はそのようなケースに遭遇したことはありませんが、
乱数の範囲計算式は他にも数種類あるので、ぶつかってしまった時は右辺値を変えて逃げるか、
別の式を用いるなどすればいいでしょう。

次回はC/C++の三種類のループのひとつ、 for についての予定です。

[前へ]   [目次へ]   [次へ]

プログラミング講座 総合目次

最終更新 2008/10/16