Wygeneruj binarny dziesiętny. Zamiast jawnego przechowywania, wystarczy śledzić minimalne i maksymalne możliwe wartości. Gdy te wartości znajdą się w tej samej liczbie całkowitej, zwróć tę liczbę całkowitą. Szkic kodu znajduje się poniżej.
(Edytuj) Pełniejsze wyjaśnienie: Powiedz, że chcesz wygenerować losową liczbę całkowitą od 1 do 3 włącznie z prawdopodobieństwem 1/3. Robimy to, generując losową rzeczywistą liczbę binarną dziesiętną x w zakresie (0, 1). Jeśli x <1/3, zwraca 1, w przeciwnym razie jeśli x <2/3 zwraca 2, w przeciwnym razie zwraca 3. Zamiast jawnego generowania cyfr dla x, po prostu śledzimy minimalne i maksymalne możliwe wartości x. Początkowo minimalna wartość x wynosi 0, a maksymalna to 1. Jeśli najpierw odwrócisz głowy, pierwsza cyfra x za przecinkiem dziesiętnym (binarnie) wynosi 1. Minimalna możliwa wartość x (binarnie) następnie wynosi 0,100000 = 1/2, a maksimum to 0.111111111 = 1. Teraz, jeśli twój następny rzut to reszka, x zaczyna się od 0.10. Minimalna możliwa wartość to 0,1000000 = 1/2, a maksymalna to 0,1011111 = 3/4. Minimalna możliwa wartość x wynosi 1/2, więc wiesz, że ” nie ma szansy na zwrócenie 1, ponieważ wymaga to x <1/3. Nadal możesz zwrócić 2, jeśli x kończy się na 1/2 <x <2/3 lub 3, jeśli 2/3 <x <3/4. Załóżmy teraz, że trzeci rzut to ogony. Wtedy x musi zaczynać się od 0.100. Min. = 0,10000000 = 1/2, a maks. = 0,100111111 = 5/8. Odkąd 1/3 <1/2 <5/8 <2/3 wiemy, że x musi mieścić się w przedziale (1/3, 2/3), więc możemy przestać generować cyfry x i po prostu zwrócić 2.
Kod robi to w zasadzie, z wyjątkiem tego, że zamiast generować x między 0 a 1, generuje x między a i b, ale zasada jest taka sama.
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
Uwaga: Przetestowałem ten kod pod kątem metody akceptowania / odrzucania i oba dają jednolite rozkłady. Ten kod wymaga mniejszej liczby rzutów monetą niż akceptacja odrzucenia, z wyjątkiem sytuacji, gdy b - a jest bliskie następnej potędze 2. Np. Jeśli chcesz wygenerować a = 0, b = 62, wtedy lepiej zaakceptować / odrzucić. Udało mi się udowodnić, że ten kod może użyć średnio nie więcej niż 2 rzutów monetą niż zaakceptować / odrzucić. Z mojego czytania wynika, że Knuth i Yao (1976) podali metodę rozwiązania tego problemu i udowodnili, że ich metoda jest optymalna pod względem oczekiwanej liczby rzutów monetą. Udowodnili ponadto, że oczekiwana liczba rzutów musi być większa niż entropia rozkładu Shannona. Nie mogłem jednak znaleźć kopii tekstu artykułu i byłbym ciekawy, jaka jest ich metoda. (Aktualizacja: właśnie znalazłem wystawę Knuth Yao 1976 tutaj:http://www.nrbook.com/devroye/Devroye_files/chapter_fifteen_1.pdf, ale jeszcze tego nie przeczytałem). Ktoś wspomniał także o Han Hoshi w tym wątku, który wydaje się bardziej ogólny, i rozwiązuje go za pomocą stronniczej monety. Zobacz także http://paper.ijcsns.org/07_book/200909/20090930.pdf autor: Pae (2009), aby uzyskać dobre omówienie literatury.