Это фактически тот же алгоритм, который предлагает Patrick87, но он генерирует биты по одному и сразу останавливается, когда находит ответ.Это по существу связано с арифметическим кодированием .
, которое я реализовал здесь на Python.
>>> # Create a function which returns 0 or 1 with equal probability.
>>> from random import random
>>> f = lambda: int(random()<0.5)
>>> # Check
>>> sum(f() for i in range(1000000))
500251
>>> # Use that to create a biased function. You can use this
>>> # either with a rational number expressed as numerator, denominator
>>> # or with a value of p between 0 and 1. Python doesn't care whether
>>> # numbers are integers but other languages might.
>>> def biased(numer, denom = 1):
... while True:
... numer += numer
... if numer >= denom:
... numer -= denom
... if f(): return 1
... else:
... if f(): return 0
...
>>> sum(biased(0,19) for i in range(1900000))
0
>>> sum(biased(1,19) for i in range(1900000))
100096
>>> sum(biased(5,19) for i in range(1900000))
500255
>>> sum(biased(18,19) for i in range(1900000))
1799988
>>> sum(biased(19,19) for i in range(1900000))
1900000
По сути, цикл создает двоичное представление числителя / знаменателя одинпоочередно, удваивая текущее значение числителя и сравнивая со знаменателем.Затем он сравнивает это с лениво сгенерированной случайной двоичной дробью, пока не может определить, является ли случайная дробь большей или меньшей.
Хотя число вызовов базовой функции f
теоретически не ограничено, ожидаемое числоtimes biased
вызывает f
, равное 2, независимо от аргументов смещения.(Это потому, что вероятность того, что случайный поток битов будет соответствовать k
двоичным цифрам, составляет 2 -k независимо от фактических значений двоичных цифр.)