Teorik olarak en uygun algoritma
İşte gönderdiğim diğer cevapların bir gelişimi. Diğer cevap, birinden diğerinden ayrı bir dağılım oluşturmak için daha genel olan duruma genişletmenin daha kolay olması avantajına sahiptir. Aslında, diğer cevap Han ve Hoshi kaynaklı algoritmanın özel bir örneğidir.
Burada tarif edeceğim algoritma Knuth ve Yao'ya (1976) dayanmaktadır. Makalelerinde, bu algoritmanın mümkün olan en az beklenen madeni para basma sayısına ulaştığını da kanıtladılar.
Bunu göstermek için, diğer cevaplarla açıklanan Reddetme örnekleme yöntemini göz önünde bulundurun. Örnek olarak, eşit olarak 5 sayıdan birini oluşturmak istediğinizi varsayalım [0, 4]. 2'nin bir sonraki gücü 8'dir, bu nedenle madalyonu 3 kez çevirir ve 8'e kadar rastgele bir sayı oluşturur. Sayı 0 ila 4 ise, o zaman geri verirsiniz. Aksi takdirde, onu atıp 8'e kadar başka bir sayı oluşturup başarılı oluncaya kadar tekrar deneyin. Ama sayıyı attığın zaman, biraz entropi harcıyorsun. Bunun yerine attığınız numaraya, beklenti içinde ihtiyaç duyacağınız gelecekteki jeton atma sayısını azaltmak için şart koyabilirsiniz. Somut olarak, [0, 7] sayısını oluşturduğunuzda, eğer [0, 4] ise, geri dönün. Aksi takdirde, 5, 6 veya 7 olur ve her durumda farklı bir şey yaparsınız. 5 ise, yazı turayı tekrar çeviriniz ve yazı tipine göre 0 ya da 1 döndürünüz. 6 ise, yazı turasını çevirin ve 2 veya 3 döndürün. eğer kafalarsa, 4 döndür, eğer kuyruklar yeniden başlarsa.
İlk başarısızlık girişimimizden kalan entropi bize 3 vaka (5, 6 veya 7) verdi. Eğer bunu bir kenara atarsak, log2 (3) yazı turalarını fırlatıp atarız. Bunun yerine onu saklıyoruz ve 6 muhtemel vaka (5H, 5T, 6H, 6T, 7H, 7T) oluşturmak için başka bir çevirinin sonucuyla birleştiriyoruz. .
İşte kod:
# 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)