線形合同法は御存知なんですよね? そうでないならば「線形合同法」を
キーワードにGoogleで検索するなどして調べてみてください。
線形合同法によって得られる乱数が整数なのか実数なのかによって0〜99
に丸める方法が変わります。
整数の場合:
線形合同法によって乱数を発生させる関数を「int myrand();」とします。
得られる乱数が0〜MY_RAND_MAXまでの場合、以下の関数で乱数を0〜n未満
の整数に丸めることができます。
int myrand_below_n(int n)
{
int ret = 0;
do{
ret = myrand()/((MY_RAND_MAX+1UL)/n);
}while(ret >= n);
return ret;
}
引数を100で呼び出せば希望の乱数が得られます。
myrand()が上の条件に当てはまらない場合(例えば負数も返すという場合)、
条件にあてはまるようにmyrand()の戻り値を補正してください(例えば負数の
戻り値は捨てる)。
考え方としては得られた乱数を丸める値の数に均等に区切って結果を得ると
いうものです。例えば0〜49の乱数を0〜4に丸める場合、0〜9、10〜
19、20〜29、30〜39、40〜49の10個ずつ5つに区切り、順に
0・1・2・3・4を当てはめるわけです。
whileを使っているのは、myrand()で得られる乱数の個数(すなわち
MY_RAND_MAX+1UL)がnで割り切れないときに乱数が一様でなくなるのを防ぐ
ためです。例えば0〜49の乱数を0〜2に丸める場合、得られる乱数の個数
が3で割り切れないため均等に区切ることができません。そこで0〜15、
16〜31、32〜47の16個ずつ3つに区切り、残った48・49が得ら
れた場合には取得しなおすわけです。
別解としてmyrand()の戻り値をnで割った剰余を使用する方法もありますが、
出現しない値があったり、あまりランダムでない値が得られたりすることがあ
ります。
実数の場合:
線形合同法によって乱数を発生させる関数を「double myrand();」とします。
得られる乱数が0〜1未満の場合、以下の関数で乱数を0〜n未満の整数に
丸めることができます。
int myrand_below_n(int n)
{
return (int)(myrand()*n);
}
myrand()が上の条件に当てはまらない場合(例えば0〜MY_RAND_MAX
未満の実数を返すという場合)、条件にあてはまるようにmyrand()の戻り値を
補正してください(例えばMY_RAND_MAXで割る。ただしこの場合乱数が一様で
なくなる可能性があります)。
|