Algoritma optimal secara teoritis
Ini adalah peningkatan dari jawaban lain yang saya posting. Jawaban lainnya memiliki keuntungan bahwa lebih mudah untuk memperluas ke kasus yang lebih umum menghasilkan satu distribusi diskrit dari yang lain. Sebenarnya, jawaban lain adalah kasus khusus dari algoritma karena Han dan Hoshi.
Algoritma yang akan saya jelaskan di sini didasarkan pada Knuth dan Yao (1976). Dalam makalah mereka, mereka juga membuktikan bahwa algoritma ini mencapai jumlah minimum yang diharapkan dari jumlah koin yang terbalik.
Untuk menggambarkannya, pertimbangkan metode pengambilan sampel Penolakan yang dijelaskan oleh jawaban lain. Sebagai contoh, misalkan Anda ingin menghasilkan satu dari 5 angka secara seragam [0, 4]. Kekuatan 2 berikutnya adalah 8 sehingga Anda membalik koin 3 kali dan menghasilkan angka acak hingga 8. Jika jumlahnya 0 hingga 4 maka Anda mengembalikannya. Kalau tidak, Anda membuangnya dan menghasilkan nomor lain hingga 8 dan coba lagi sampai Anda berhasil. Tetapi ketika Anda membuang nomornya, Anda hanya membuang beberapa entropi. Sebagai gantinya, Anda dapat mengkondisikan jumlah yang Anda buang untuk mengurangi jumlah flips koin di masa depan yang Anda butuhkan dengan harapan. Konkretnya, begitu Anda menghasilkan angka [0, 7], jika itu [0, 4], kembalilah. Kalau tidak, ini 5, 6, atau 7, dan Anda melakukan sesuatu yang berbeda dalam setiap kasus. Jika 5, balik koin lagi dan kembalikan 0 atau 1 berdasarkan flip. Jika 6, balik koin dan kembalikan 2 atau 3. Jika 7, balik koin; jika kepala, kembalilah 4, jika ekornya mulai dari awal.
Entropi sisa dari upaya awal kami yang gagal memberi kami 3 kasus (5, 6, atau 7). Jika kita membuang ini, kita membuang log2 (3) koin membalik. Kami malah menyimpannya, dan menggabungkannya dengan hasil flip lain untuk menghasilkan 6 kemungkinan kasus (5H, 5T, 6H, 6T, 7H, 7T) yang mari kita segera mencoba lagi untuk menghasilkan jawaban akhir dengan probabilitas keberhasilan 5/6 .
Ini kodenya:
# 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)