c++
C言語ではstdlibのrand関数を用いて整数乱数を作れる。 では小数まで含めた連続な乱数が欲しくなったらどうすればよいのだろうか。 結論としては
rand() / RAND_MAXで[0.0, 1.0]の一様分布が生成できる。
#include<stdio.h>
#include <stdlib.h>
int main()
{
srand(0); // 再現性のためにseedを固定
int i = 0;
for(i = 0; i < 10; i++)
{
double rnd = (double)rand() / RAND_MAX;
printf("%f\n", rnd);
}
return 0;
}
これを実行すると
$ gcc rnd.c $ ./a.out 0.840188 0.394383 0.783099 0.798440 0.911647 0.197551 0.335223 0.768230 0.277775 0.553970のように0から1までの値が大体均等に出ていることが確認できる。
細かいポイントであるが、このコードの場合値域は閉区間である。 つまりちょうど0や1が出現することは、低い確率であるがある。 数学的には連続一様分布から0や1が出現する確率は0である(というか どうんな数でもピッタリあった数が出現することは確率0である) が、プログラミング上は離散的に近似しているしている影響で、 0より大きい確率 1 / (RAND_MAX + 1) で0と1が出現する。 すなわち0や1がでたら困るようなコードを後段に入れてはいけない。
とはいえ0や1が出てはどうしても困る用途もあるだろう。その場合は 分母や分子に1を足すことで対処することができる。
rand() / RAND_MAXとする箇所で
- rand() / RAND_MAX: [0, 1]
- rand() / (RAND_MAX + 1): [0, 1)
- (rand() + 1) / (RAND_MAX + 1): (0, 1]
- (rand() + 1) / (RAND_MAX + 2): (0, 1)
おすすめ記事
C++ STLで0から1の実数値乱数を生成するstd::vector<bool>はテンプレート特殊化して別物になっている
C++ std::mapを値入りで初期化するのは初期化子リストでOK
同人ゲーム・イラストなど