ผมคิดว่า (ดังนั้นจึงสามารถจะผิด :-) นี้วิธีการแก้ปัญหาที่ใช้ในการสับเปลี่ยน Fisher-Yates เพื่อให้การกระจายอย่างสม่ำเสมอมีการประมาณที่ดี (ดูหัวข้อแก้ไขด้านล่าง) ในการวนซ้ำทุกครั้งคุณสามารถใช้เคล็ดลับนี้เพื่อสร้างค่าระหว่าง0ถึงk - 1 :O ( N2)krand
0k - 1
// return a random number in [0..k-1] with uniform distribution
// using a uniform random generator in [1..50]
funtion krand(k) {
sum = 0
for i = 1 to k do sum = sum + RandNum50() - 1
krand = sum mod k
}
อัลกอริทึม Fisher-Yates กลายเป็น:
arr : array[0..99]
for i = 0 to 99 do arr[i] = i+1; // store 1..100 in the array
for i = 99 downto 1 {
r = krand(i+1) // random value in [0..i]
exchange the values of arr[i] and arr[r]
}
for i = 0 to 99 do print arr[i]
แก้ไข:
ตามที่เอริคชี้ให้เห็นkrand
ฟังก์ชั่นด้านบนไม่ได้ให้การกระจายที่เหมือนกันอย่างแท้จริง มีวิธีการอื่น ๆ ที่สามารถใช้ในการรับที่ดีกว่า (โดยพลการดีกว่า) และประมาณได้เร็วขึ้น; แต่ (ขึ้นอยู่กับความรู้ของฉัน) วิธีเดียวที่จะได้รับเครื่องแบบกระจายอย่างแท้จริงคือการใช้การสุ่มตัวอย่างปฏิเสธ : รับบิตสุ่มและถ้าจำนวนRได้รับน้อยกว่าkผลตอบแทนมันสร้างอย่างอื่น อีกจำนวนสุ่ม การใช้งานที่เป็นไปได้:m = ⌈ บันทึก2( k ) ⌉Rk
function trulyrand(k) {
if (k <= 1) return 0
while (true) { // ... if you're really unlucky ...
m = ceil(log_2 (k) ) // calculate m such that k < 2^m
r = 0 // will hold the random value
while (m >= 0) { // ... will add m bits
if ( rand50() > 25 ) then b = 1 else b = 0 // random bit
r = r * 2 + b // shift and add the random bit
m = m - 1
}
if (r < k) then return r // we have 0<=r<2^m ; accept it, if r < k
}
}