あなたの質問を言い換えさせてください:
を 上の離散random()
一様分布を持つ乱数発生器とし[0,1)
ます。によって返さD
れる可能性のある値の数を とします。それぞれの値は前の値よりもrandom()
正確に大きくなります。可能な各値が前の値より正確に大きくなるように、離散一様分布で1/D
乱数発生器を作成します。rand(L, U)
[L, U)
1/D
--
いくつかの簡単なメモ。
- この形式の問題は、あなたが言ったように解決できません。つまり、N = 1 の場合、私たちにできることは何もありません。
0.0
の可能な値の 1 つである必要はありませんrandom()
。そうでない場合は、次の場合に以下のソリューションが失敗する可能性がありますU - L < 1 / D
。その場合は特に気になりません。
- 分析が簡単になるので、すべて半開範囲を使用します。閉じた範囲を使用するのは簡単ですが、面倒です。
最後に、良いもの。ここでの重要な洞察は、結果の全体部分と小数部分を個別に選択することによって密度を維持できるということです。
random()
まず、作成するのは簡単であることに注意してくださいrandomBit()
。あれは、
randomBit() { return random() >= 0.5; }
次に、{0, 1, 2, ..., 2^N - 1}
一様にランダムにいずれかを選択したい場合は、 を使用して簡単randomBit()
に、各ビットを生成するだけです。これを呼び出しますrandom2(N)
。
を使用して、次random2()
のいずれかを選択できます{0, 1, 2, ..., N - 1}
。
randomInt(N) { while ((val = random2(ceil(log2(N)))) >= N); return val; }
ここで、D
が既知の場合、問題は自明です。なぜなら、floor((U - L) * D)
値の 1 つをランダムに一様に選択するだけに減らすことができ、それを で行うことができるからですrandomInt()
。
D
したがって、それは知られていないと仮定しましょう。[0, 2^N)
それでは、まず適切な密度の範囲でランダムな値を生成する関数を作成しましょう。これは簡単です。
rand2D(N) { return random2(N) + random(); }
rand2D()
連続する可能な値の差random()
が正確であることが必要な場所です1/D
。そうでない場合、ここで可能な値の密度は均一ではありません。
[0, V)
次に、適切な密度の範囲内の値を選択する関数が必要です。これはrandomInt()
上記と同様です。
randD(V) { while ((val = rand2D(ceil(log2(V)))) >= V); return val; }
そして最後に...
rand(L, U) { return L + randD(U - L); }
L / D
が整数でない場合、離散位置をオフセットした可能性がありますが、それは重要ではありません。
--
最後に、これらの関数のいくつかは決して終了しないことに気付いたかもしれません。それは本質的に要件です。たとえば、random()
ランダム性が 1 ビットしかない場合があります。次に、3 つの値のいずれかを選択するように求めた場合、終了が保証されている関数を使用して一様にランダムに選択することはできません。