อัลกอริธึมที่เหมาะสมที่สุดในเชิงทฤษฎี
นี่คือการปรับปรุงคำตอบอื่น ๆ ที่ฉันโพสต์ คำตอบอื่น ๆ มีข้อได้เปรียบที่ง่ายต่อการขยายไปยังกรณีทั่วไปมากขึ้นในการสร้างการกระจายแบบแยกจากที่หนึ่ง ในความเป็นจริงคำตอบอื่น ๆ เป็นกรณีพิเศษของอัลกอริทึมเนื่องจากฮันและ Hoshi
อัลกอริทึมที่ฉันจะอธิบายที่นี่ขึ้นอยู่กับ Knuth และ 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) ซึ่งให้เราลองใหม่อีกครั้งเพื่อสร้างคำตอบสุดท้ายด้วยความน่าจะเป็นที่ประสบความสำเร็จ 5/6 .
นี่คือรหัส:
# 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)