intをランダムビットで埋めるアプローチは、私の意見では正しい方法です。しかし、あなたのアルゴリズムは唯一最大の2の累乗であると、ループ内のいずれかでオフになっているとき、私はこの変更をお勧めしたい作品以来:
// max number of bits
int i = (int)Math.floor(Math.log(max)/Math.log(2)) + 1;
int rnd = 0;
int mask = 1;
while (i-- > 0) {
rnd = rnd << 1 | randBit();
mask <<= 1; // or: mask *= 2
}
double q = (double)rnd/mask; // range is [0, 1)
return (int)((max + 1) * q);
さんはこれを見てみましょう:
i
ます常にmax
が占有するビット数と等しくなければなりません。ループが終了すると、rnd
は0または1でランダムに埋められたビット数を含み、mask-1
は1で満たされたビット数を含みます。したがって、rnd
とmask-1
の商が0と1との間に均等に分布していると仮定することは安全です。max
を乗じると0〜max
の範囲の結果が浮動/実数の値として均等に分布します。
この結果は整数にマッピングする必要があります。もちろん、これらの値を一様に分散したい場合もあります。ここで唯一のキャッチは1です。rnd
とmask-1
の商がちょうど1の場合、希望の結果範囲にスケーリングするときに問題を引き起こすエッジケースがあります。0 .. max-1
の値が均一に分布しますが、max
はまれな例外です。
この条件を処理するには、商が0から1の範囲になるように1 となるように商を構築する必要があります。これはrnd/mask
によって達成されます。この範囲は、max+1
を乗算してintにキャストすることで、均一に広げられた整数0 .. max
に簡単にマッピングできます。
アプローチは、2の累乗(または2のべき乗-1:「最大」が包括的か排他的かを明確にしていない)では合理的ですが、その数が2の累乗でない場合たとえば、「max」が6の場合。 – BeeOnRope
maxが2の場合、0〜7の間の結果が得られます。 – yacc