はじめに
IEEE 754に従って, 一様分布な[0, 1)の浮動小数点数を作るにはこれしかないのではないか, というはなし.
ランダムな浮動小数点数
ランダムな[0, 1)を作ろうとすると次のようになると思われます. このような無茶苦茶な?型変換ができない言語でも結果的にこんな感じになっていると思われます. 応用すると, (-1, 1)の範囲なども簡単に実現できます.
float frand01(uint32_t x)
{
static const uint32_t m0 = 0x3F800000U;
static const uint32_t m1 = 0x007FFFFFU;
x = m0|(x&m1);
return std::bit_cast<float, uint32_t>(x) - 1.000000000f;
}
まとめ
完全かと言われると, そうなるわけがないです. 浮動小数点数が表現できる数の分布が偏っているので, どうやっても不可能です. 固定小数点数を使うべきです.
頑張ればできるのかな?私は頭が悪いので効率的な方法を思いつかないです.
追記
浮動小数点数のはなしなのに、固定小数点数を使えって何を言っているのか.
制限
制限を書いてないのは不公平でした.
- 結果に関わる計算に, 結果より高精度の演算を使わない
- 速いと嬉しい
- 今時, 割り算でも大した速度差ない気がしますけど
(-1, 1)の. @fujitanozomuさんの方法だと精度が上がって, 0.999999940fが上限になるので引き算する定数も変わります.
手で演算をまとめると3.0の方が近いので結果が異なります.
float frand11(uint32_t x)
{
static const uint32_t m0 = 0x40000000U;
static const uint32_t m1 = 0x007FFFFFU;
x = m0|(x&m1);
return std::bit_cast<float, uint32_t>(x) - 2.0f - 0.999999881f;
}
STLは大体こんな感じだった気がします.
float frand01()
{
while(true){
uint32_t x = (一様乱数);
float result = x * (浮動小数点数の表現できる最大整数値)/(乱数の最大値);
if(result<1.0f){
return result;
}
}
}