เกี่ยวข้องกับการrand() % n
เป็นน้อยกว่าอุดมคติ
การทำrand() % n
มีการกระจายที่ไม่สม่ำเสมอ คุณจะได้รับจำนวนค่าที่ไม่สมส่วนเนื่องจากจำนวนของค่าไม่ได้เป็นหลายเท่าของ 20
ถัดไปrand()
โดยทั่วไปเป็นเครื่องกำเนิดไฟฟ้าเชิงเส้นเชิงเส้น (มีคนอื่น ๆ อีกมากมายเพียงแค่นี้เป็นหนึ่งในการดำเนินการมากที่สุด - และมีพารามิเตอร์ที่เหมาะน้อยกว่า (มีหลายวิธีในการเลือกพารามิเตอร์)) ปัญหาที่ใหญ่ที่สุดของเรื่องนี้คือบ่อยครั้งที่บิตต่ำในมัน (สิ่งที่คุณได้รับจาก% 20
นิพจน์ประเภท) ไม่ใช่การสุ่ม ฉันจำได้หนึ่งrand()
ปีที่ผ่านมาที่บิตต่ำสุดสลับจาก1
ไปยัง0
กับการโทรแต่ละครั้งrand()
- มันไม่ได้สุ่มมาก
จากหน้าแรนด์ (3) หน้า:
เวอร์ชันของ rand () และ srand () ใน Linux C Library ใช้เหมือนกัน
ตัวสร้างตัวเลขสุ่มเป็น random () และ srandom () ดังนั้นลำดับที่ต่ำกว่า
บิตควรเป็นแบบสุ่มเช่นเดียวกับบิตลำดับสูงกว่า อย่างไรก็ตามเมื่ออายุมากขึ้น
การใช้งานแรนด์ () และการใช้งานในปัจจุบันที่แตกต่างกัน
ระบบบิตที่มีลำดับต่ำกว่านั้นจะสุ่มน้อยกว่าค่าที่สูงกว่า -
บิตสั่งซื้อ อย่าใช้ฟังก์ชั่นนี้ในแอพพลิเคชั่นที่ต้องการ
แบบพกพาเมื่อจำเป็นต้องมีการสุ่มที่ดี
ตอนนี้อาจถูกลดชั้นลงไปในประวัติศาสตร์ แต่เป็นไปได้ว่าคุณยังมีแรนด์ที่แย่ () การใช้งานซ่อนตัวอยู่ที่ไหนสักแห่งในกองซ้อน ในกรณีนี้มันยังใช้งานได้ค่อนข้าง
สิ่งที่ต้องทำคือการใช้ห้องสมุดเลขสุ่มที่ดี (ที่ให้ตัวเลขสุ่มที่ดี) แล้วขอตัวเลขสุ่มภายในช่วงที่คุณต้องการ
ตัวอย่างของรหัสสุ่มบิตที่ดี (จาก 13:00 ในวิดีโอที่เชื่อมโยง)
#include <iostream>
#include <random>
int main() {
std::mt19937 mt(1729); // yes, this is a fixed seed
std::uniform_int_distribution<int> dist(0, 99);
for (int i = 0; i < 10000; i++) {
std::cout << dist(mt) << " ";
}
std::cout << std::endl;
}
เปรียบเทียบสิ่งนี้กับ:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
srand(time(NULL));
for (int i = 0; i < 10000; i++) {
printf("%d ", rand() % 100);
}
printf("\n");
}
เรียกใช้โปรแกรมเหล่านี้ทั้งสองและเปรียบเทียบความถี่ที่จำนวนที่แน่นอนเกิดขึ้น (หรือไม่เกิดขึ้น) ในผลลัพธ์นั้น
วิดีโอที่เกี่ยวข้อง: rand () ถือว่าเป็นอันตราย
บางแง่มุมทางประวัติศาสตร์ของแรนด์ () ก่อให้เกิดข้อบกพร่องใน Nethack ที่เราควรดูและพิจารณาในการใช้งานของตัวเอง:
แก้ไขปัญหา RNG
Rand () เป็นฟังก์ชันพื้นฐานสำหรับการสร้างหมายเลขสุ่มของ Nethack วิธีที่ Nethack ใช้คือบั๊กกี้หรืออาจเป็นที่ถกเถียงกันอยู่ว่า lrand48 () สร้างตัวเลขสุ่มหลอกเส็งเคร็ง (อย่างไรก็ตาม lrand48 () เป็นฟังก์ชั่นห้องสมุดโดยใช้วิธี PRNG ที่กำหนดไว้และโปรแกรมใด ๆ ที่ใช้มันควรคำนึงถึงจุดอ่อนของวิธีการนั้น)
ข้อผิดพลาดคือ Nethack อาศัย (บางครั้งก็เป็นเช่นเดียวกับใน rn (2)) ที่บิตด้านล่างของผลลัพธ์จาก lrand48 () ด้วยเหตุนี้ RNG ในเกมทั้งหมดจึงใช้งานไม่ได้ สิ่งนี้เป็นสิ่งที่สังเกตได้โดยเฉพาะก่อนที่การกระทำของผู้ใช้จะนำมาซึ่งการสุ่มเพิ่มเติมเช่นในการสร้างตัวละครและการสร้างระดับแรก
ในขณะที่ข้างต้นมาจากปี 2003 มันควรจะยังคงเก็บไว้ในใจเพราะมันอาจจะไม่ใช่กรณีที่ระบบทั้งหมดที่ใช้งานเกมที่คุณต้องการจะเป็นระบบ Linux ที่ทันสมัยพร้อมฟังก์ชั่น rand () ที่ดี
หากคุณเพียงแค่ทำสิ่งนี้ด้วยตัวคุณเองคุณสามารถทดสอบว่าตัวสร้างตัวเลขสุ่มของคุณดีแค่ไหนโดยการเขียนโค้ดและทดสอบผลลัพธ์ด้วยเอนท์
เกี่ยวกับคุณสมบัติของตัวเลขสุ่ม
มีการตีความอื่น ๆ ของ 'สุ่ม' ที่ไม่ได้สุ่มอย่างแน่นอน ในสตรีมข้อมูลแบบสุ่มเป็นไปได้ค่อนข้างมากที่จะได้รับหมายเลขเดียวกันสองครั้ง หากคุณพลิกเหรียญ (สุ่ม) เป็นไปได้มากทีเดียวที่จะได้รับสองหัวติดต่อกัน หรือโยนลูกเต๋าสองครั้งแล้วรับหมายเลขเดียวกันสองครั้งติดต่อกัน หรือหมุนวงล้อรูเล็ตและรับหมายเลขเดียวกันสองครั้ง
การแจกแจงของตัวเลข
เมื่อเล่นรายการเพลงผู้คนคาดหวังว่า 'สุ่ม' หมายความว่าเพลงหรือศิลปินเดียวกันจะไม่เล่นเป็นครั้งที่สองติดต่อกัน การมีเพลย์ลิสต์เล่น The Beatles สองครั้งติดกันถือว่าไม่ 'สุ่ม' (แม้ว่าจะเป็นการสุ่ม) การรับรู้ว่าสำหรับรายการเพลงสี่เพลงเล่นทั้งหมดแปดครั้ง:
1 3 2 4 1 2 4 3
มี 'สุ่ม' มากกว่า:
1 3 3 2 1 4 4 2
เพิ่มเติมเกี่ยวกับสิ่งนี้สำหรับ 'การสับ' ของเพลง: วิธีการสลับเพลงได้อย่างไร
เกี่ยวกับค่าซ้ำ
หากคุณไม่ต้องการที่จะทำซ้ำค่ามีวิธีการที่แตกต่างกันที่ควรพิจารณา สร้างค่าที่เป็นไปได้ทั้งหมดและสลับค่า
หากคุณกำลังโทรrand()
(หรือเครื่องกำเนิดหมายเลขสุ่มอื่น ๆ ) คุณกำลังโทรหาด้วยการแทนที่ คุณสามารถรับหมายเลขเดิมสองครั้งได้เสมอ ทางเลือกหนึ่งคือการโยนค่าซ้ำแล้วซ้ำอีกจนกว่าคุณจะเลือกตัวเลือกที่ตรงกับความต้องการของคุณ ฉันจะชี้ให้เห็นว่านี่เป็นรันไทม์แบบไม่ จำกัด และเป็นไปได้ที่คุณจะพบว่าตัวเองอยู่ในสถานการณ์ที่มีการวนซ้ำไม่สิ้นสุดเว้นแต่คุณจะเริ่มทำการสืบค้นกลับที่ซับซ้อนมากขึ้น
รายการและเลือก
ตัวเลือกอื่นคือการสร้างรายการของสถานะที่ถูกต้องทั้งหมดที่เป็นไปได้แล้วเลือกองค์ประกอบแบบสุ่มจากรายการนั้น ค้นหาจุดที่ว่างเปล่าทั้งหมด (ที่ตรงตามกฎบางอย่าง) ในห้องจากนั้นเลือกจุดสุ่มจากรายการนั้น จากนั้นทำอีกครั้งและอีกครั้งจนกว่าจะเสร็จ
สับเปลี่ยน
อีกวิธีคือการสับไพ่ราวกับว่าเป็นไพ่ เริ่มต้นด้วยสปอตที่ว่างเปล่าทั้งหมดในห้องจากนั้นเริ่มกำหนดสปอตโดยการจัดการสปอตที่ว่างเปล่าทีละครั้งสำหรับแต่ละกฎ / กระบวนการเพื่อขอสปอตที่ว่างเปล่า คุณทำเสร็จเมื่อการ์ดหมดหรือสิ่งที่หยุดขอ