あなたが観察したように、ビットを連結することにより、可能なランダム値の範囲を2のべき乗で繰り返し2倍にすることができますが、整数のビット数(ゼロなど)で開始すると、素因数以外の範囲を取得することはできません2。
いくつかの方法があります。どれも理想的ではありません:
- 必要な範囲よりも大きい最初の到達可能な範囲を生成し、結果を破棄して、ランダム値が目的の範囲外にある場合は最初からやり直します。
- 非常に大きな範囲を生成し、それを目的の出力にできるだけ均等に分配し、得られる小さなバイアスを見落とします。
- 非常に広い範囲を生成し、希望する出力間で均等に分配できるものを分配し、均等に分配されるセットから外れる [比例的に] 少数の値の 1 つにヒットした場合は、結果を破棄して最初からやり直します。
- 3 と同様ですが、結果に変換しなかった値の部分を再利用します。
最初のオプションは常に良い考えではありません。番号 2 と 3 はかなり一般的です。ランダムなビットが安価な場合、通常は 3 が最速のソリューションであり、頻繁に繰り返される可能性はかなり低くなります。
最後の 1 つ。[0,31] でランダムな値を構築したと仮定し、そこから結果[0,5]r
を生成する必要があります。x
[0,29]の値はr
mod 6 を使用してバイアスなしで必要な出力にマッピングできますが、[30,31] の値はバイアスを避けるためにフロアにドロップする必要があります。
前者の場合、有効な結果が生成されますx
が、さらにランダム性が残っています。範囲 [0,5]、[6,11] などの差 (この場合は 5 つの可能な値) です。r
これを使用して、生成する必要がある次のランダム値の新しい構築を開始できます。
後者の場合、何も取得できず、再試行する必要がありますが、すべてをx
破棄する必要はありません。不正な範囲 [30,31] から選択された特定の値は残り、次の開始値として自由に使用できます (2 つの可能な値)。r
r
その時点からのランダムな範囲は、2 の累乗である必要はありません。その時点で必要な範囲に魔法のように到達するという意味ではありませんが、捨てるものを最小限に抑えることができるということです.
を大きくすればするr
ほど、オーバーフローした場合により多くのビットを破棄する必要がありますが、その可能性は低くなります。1 ビットを追加するとリスクは半分になりますが、コストは直線的に増加するだけなので、r
処理できる最大のものを使用するのが最善です。