コインが1つあります。何度でも反転できます。
ような乱数を生成します。ここで、です。
数字の分布は均一でなければなりません。
あれば簡単です:
r = a + binary2dec(flip n times write 0 for heads and 1 for tails)
どのような場合?
コインが1つあります。何度でも反転できます。
ような乱数を生成します。ここで、です。
数字の分布は均一でなければなりません。
あれば簡単です:
r = a + binary2dec(flip n times write 0 for heads and 1 for tails)
どのような場合?
回答:
探しているのは、リジェクションサンプリングまたはaccept-rejectメソッドに基づいています(Wikiページは少し技術的であることに注意してください)。
このメソッドは、このような状況で役立ちます。セットからランダムなオブジェクト(場合によってはセットランダムな整数)を選択したいのですが、その方法はわかりませんが、ことができる(あなたの場合の第1のセットを含むより大きなセットからいくつかのランダムなオブジェクトを選択し、[ 、2 K + A ]一部のKように2 K + ≥ B ;この対応するk個のコインが反転)。
このようなシナリオでは、小さいセットの要素をランダムに選択するまで、大きいセットから要素を選択し続けるだけです。小さいセットが大きいセットに比べて十分に大きい場合(あなたの場合、は[ a 、b ]の最大2倍の整数が含まれます)、これは効率的です。
別の例:半径1の円の中のランダムな点を選択したいとします。今、このための直接的な方法を考えるのは本当に簡単ではありません。accept-rejectメソッドを使用します。円を囲む1x1の正方形でポイントをサンプリングし、描画する数値が円の内側にあるかどうかをテストします。
(専門的:答えは数の選択をフィット)
あなたが望むようあなたが何回として、あなたのコインを投げるために許可されているので、近い-AS-あなた-願いとして均一に分数選ぶことによって、あなたの確率を得ることができあなたが反転:(バイナリ基数を使用して点後の各桁のコイン)と乗算RによってBA 0及び[BA-1]との間の数(整数に切り捨て)を取得します。この番号をaに追加すれば完了です。
例:と言います。バイナリの1/3は0.0101010101 ....そして、フリップが0〜0.010101 ...の場合、ピックはbです。それはbeween 0.010101 ...と0.10101010であれば...あなたのピックになります+ 1、及びそれ以外の場合は次のようになります+ 2。
コインを回フリップすると、aとbの間の各数字が確率1で選択されます1。
2範囲の次に大きい力、およびより大きい廃棄回答に数選択。
n = b-a;
N = round_to_next_larger_power_of_2(n)
while (1) {
x = random(0 included to N excluded);
if (x < n) break;
}
r = a + x;
baが2のべき乗でない場合、結果を得るために多くのコインを裏返す必要があります。結果が得られないこともありますが、極端な場合はほとんどありません。
方法
最も単純な方法は、[a、b)に着地するまで、[a、a + 2 ^ n)の数を生成することです(2 ^ n> = ba)。この方法で多くのエントロピーを捨てます。
より高価な方法では、すべてのエントロピーを維持することができますが、コインフリップ/サイコロの数が増えると計算量が非常に高くなります。直観的には、コインフリップを小数点の右側の2進数の数字として扱い、その数値を2から2からabに変換し、「スタック」したときにその数字の数字を返すようなものです。
例
次のコードは、フェアnサイドダイスのロールをフェアmサイドダイスのロール(あなたの場合はn = 2、m = ab)に変換します。ロールの数が増えると、限界コストが増加します。任意の精度のRational数値型の必要性に注意してください。良い特性の1つは、数字がスタックしなければならないために数回ロールすることで遅延する可能性がありますが、nサイドからmサイドに変換し、nサイドに戻すことです。
public static IEnumerable<BigInteger> DigitConversion(this IEnumerable<BigInteger> inputStream, BigInteger modIn, BigInteger modOut) {
//note: values are implicitly scaled so the first unfixed digit of the output ranges from 0 to 1
Rational b = 0; //offset of the chosen range
Rational d = 1; //size of the chosen range
foreach (var r in inputStream) {
//narrow the chosen range towards the real value represented by the input
d /= modIn;
b += d * r;
//check for output digits that have become fixed
while (true) {
var i1 = (b * modOut).Floor();
var i2 = ((b + d) * modOut).Floor(); //note: ideally b+d-epsilon, but another iteration makes that correction unnecessary
if (i1 != i2) break; //digit became fixed?
//fix the next output digit (rescale the range to make next digit range from 0 to 1)
d *= modOut;
b *= modOut;
b -= i1;
yield return i1;
}
}
}
2進数の10進数を生成します。明示的に保存する代わりに、可能な最小値と最大値を追跡します。それらの値が同じ整数内に収まったら、その整数を返します。コードのスケッチは次のとおりです。
(編集)完全な説明:1/3の確率でそれぞれ1から3までのランダムな整数を生成するとします。これを行うには、範囲(0、1)のランダムな2進10進実数xを生成します。x <1/3の場合、1を返します。x<2/3の場合、2を返します。3を返します。xの数字を明示的に生成する代わりに、xの最小値と最大値を追跡します。最初は、xの最小値は0で、最大は1です。最初に頭を反転させると、小数点の後ろのxの最初の桁(バイナリ)は1です。xの最小値(バイナリ)は0.100000になります。 = 1/2で、最大値は0.111111111 = 1です。次のフリップがテールの場合、xは0.10から始まります。可能な最小値は0.1000000 = 1/2で、最大値は0.1011111 = 3/4です。xの可能な最小値は1/2なので、そこにあることがわかります s x <1/3が必要なため、1を返す可能性はありません。xが1/2 <x <2/3の場合は2を返し、2/3 <x <3/4の場合は3を返します。次に、3番目のフリップがテールであるとします。次に、xは0.100で始まる必要があります。最小= 0.10000000 = 1/2および最大= 0.100111111 = 5/8。1/3 <1/2 <5/8 <2/3であるため、xが間隔(1 / 3、2 / 3)に収まらなければならないことがわかっているため、xの数字の生成を停止し、2を返すだけです。
コードは、0と1の間でxを生成する代わりに、aとbの間でxを生成することを除いて、本質的にこれを行いますが、原理は同じです。
def gen(a, b):
min_possible = a
max_possible = b
while True:
floor_min_possible = floor(min_possible)
floor_max_possible = floor(max_possible)
if max_possible.is_integer():
floor_max_possible -= 1
if floor_max_possible == floor_min_possible:
return floor_max_possible
mid = (min_possible + max_possible)/2
if coin_flip():
min_possible = mid
else:
max_possible = mid
注:このコードを受け入れ/拒否方法に対してテストしたところ、両方とも均一な分布が得られました。このコードは、b-aが次の2のべき乗に近い場合を除いて、拒否を受け入れるよりもコインフリップが少なくて済みます。このコードで使用できるコインフリップは、受け入れ/拒否よりも平均で2つまでしか使用できないことを証明できました。私の読書から、Knuth and Yao(1976)がこの問題を解決する方法を提供し、それらの方法が予想されるコインフリップの回数で最適であることを証明したようです。さらに、予想されるフリップの数は、分布のシャノンエントロピーよりも大きくなければならないことを証明しました。しかし、私は論文のテキストのコピーを見つけることができず、彼らの方法が何であるかを知りたいと思うでしょう。(更新:1976年にKnuth Yaoの博覧会を見つけました:http://www.nrbook.com/devroye/Devroye_files/chapter_fifteen_1.pdfです が、まだ読んでいません。誰かがこのスレッドでHan Hoshiに言及しましたが、これはより一般的であるようで、偏ったコインを使用して解決します。文献のよい議論については、Pae(2009)によるhttp://paper.ijcsns.org/07_book/200909/20090930.pdfも参照してください。
これは、b-aが2 ^ kに等しくない場合の提案された解決策です。一定のステップ数で動作することになっています(予想範囲外の候補者を捨てる必要はありません)。
ただし、これが正しいかどうかはわかりません。この乱数ジェネレーター(存在する場合)の正確な不均一性と、それを測定/定量化する方法を批判し、説明してください。
まず、範囲[0、z-1]で一様に分布した乱数を生成する同等の問題に変換します。ここで、z = b-aです。
また、m = 2 ^ kを2> = zの最小乗とします。
上記の解決策に従って、範囲[0、m-1]に一様に分布した乱数ジェネレーターR(m)が既にあります(各ビットに1つずつkコインを投げることで実行できます)。
Keep a random seed s and initialize with s = R(m).
function random [0, z-1] :
x = R(m) + s
while x >= z:
x -= z
s = x
return x
whileループは最大3回実行され、次の乱数を一定のステップ数で与えます(ベストケース=ワーストケース)。
数字[0,2]のテストプログラムはこちらをご覧ください:http : //pastebin.com/zuDD2V6H
理論的に最適なアルゴリズム
ここに私が投稿した他の回答の改善点があります。もう1つの答えには、1つの離散分布を別の分布から生成するより一般的な場合に簡単に拡張できるという利点があります。実際、もう1つの答えは、HanとHoshiによるアルゴリズムの特殊なケースです。
ここで説明するアルゴリズムは、Knuth and Yao(1976)に基づいています。彼らの論文では、彼らはまた、このアルゴリズムがコインフリップの可能な最小数を達成することを証明しました。
それを説明するために、他の回答で説明されている拒否サンプリング方法を検討してください。例として、5つの数値のいずれかを一様に生成するとします[0、4]。次の2の累乗は8なので、コインを3回フリップし、最大8個の乱数を生成します。数字が0〜4の場合、それを返します。それ以外の場合は、それを破棄して最大8個の別の番号を生成し、成功するまで再試行します。しかし、数字を捨てると、エントロピーが無駄になります。代わりに、投げた数字を条件にして、将来必要になるコインフリップの数を減らすことができます。具体的には、数値[0、7]を生成したら、それが[0、4]であれば戻ります。それ以外の場合、5、6、または7であり、それぞれの場合に異なることを行います。5の場合、コインを再度フリップし、フリップに基づいて0または1を返します。6の場合 コインを裏返し、2または3を返します。7の場合、コインを裏返します。頭の場合は4を返し、尾の場合は最初からやり直します。
最初に失敗した試行からの残りのエントロピーにより、3つのケース(5、6、または7)が得られました。これを捨てるだけなら、log2(3)コインフリップを捨てます。代わりにそれを保持し、別のフリップの結果と組み合わせて、6つの可能なケース(5H、5T、6H、6T、7H、7T)を生成します。 。
コードは次のとおりです。
# returns an int from [0, b)
def __gen(b):
rand_num = 0
num_choices = 1
while True:
num_choices *= 2
rand_num *= 2
if coin.flip():
rand_num += 1
if num_choices >= b:
if rand_num < b:
return rand_num
num_choices -= b
rand_num -= b
# returns an int from [a, b)
def gen(a, b):
return a + __gen(b - a)