Tôi dường như thấy nhiều câu trả lời trong đó ai đó đề xuất sử dụng <random>
để tạo các số ngẫu nhiên, thường cùng với mã như thế này:
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 5);
dis(gen);
Thông thường điều này thay thế một số loại "sự ghê tởm xấu xa" chẳng hạn như:
srand(time(NULL));
rand()%6;
Chúng ta có thể chỉ trích cách làm cũ bằng cách lập luận rằng time(NULL)
cung cấp entropy thấp, time(NULL)
có thể dự đoán được và kết quả cuối cùng là không đồng nhất.
Nhưng tất cả những điều đó đều đúng với phương pháp mới: nó chỉ có một lớp veneer sáng bóng hơn.
rd()
trả về một đơnunsigned int
. Điều này có ít nhất 16 bit và có lẽ là 32. Điều đó không đủ để tạo ra trạng thái 19937 bit của MT.Sử dụng
std::mt19937 gen(rd());gen()
(gieo hạt với 32 bit và xem xét đầu ra đầu tiên) không cung cấp phân phối đầu ra tốt. 7 và 13 không bao giờ có thể là đầu ra đầu tiên. Hai hạt tạo ra 0. Mười hai hạt tạo ra 1226181350. ( Link )std::random_device
có thể, và đôi khi được thực hiện như một PRNG đơn giản với một hạt giống cố định. Do đó, nó có thể tạo ra cùng một trình tự trên mỗi lần chạy. ( Liên kết ) Điều này thậm chí còn tồi tệ hơntime(NULL)
.
Tệ hơn nữa, rất dễ dàng sao chép và dán các đoạn mã nói trên, bất chấp các vấn đề của chúng. Một số giải pháp cho này đòi hỏi phải mua largish thư viện mà có thể không phù hợp với tất cả mọi người.
Về vấn đề này, câu hỏi của tôi là Làm cách nào để có thể gieo mầm mt19937 PRNG trong C ++ một cách ngắn gọn, dễ hiểu và kỹ lưỡng?
Với những vấn đề trên, một câu trả lời hay:
- Phải gieo đầy đủ mt19937 / mt19937_64.
- Không thể chỉ dựa vào
std::random_device
hoặctime(NULL)
như một nguồn entropy. - Không nên dựa vào Boost hoặc các quyền tự do khác.
- Nên vừa với một số dòng nhỏ để nó trông đẹp mắt khi được dán vào một câu trả lời.
Suy nghĩ
Suy nghĩ hiện tại của tôi là kết quả đầu ra từ
std::random_device
có thể được trộn (có thể thông qua XOR) vớitime(NULL)
, các giá trị bắt nguồn từ ngẫu nhiên hóa không gian địa chỉ và một hằng số được mã hóa cứng (có thể được thiết lập trong quá trình phân phối) để có được một bức ảnh nỗ lực tốt nhất tại entropy.std::random_device::entropy()
không đưa ra một dấu hiệu tốt về những gìstd::random_device
có thể hoặc không thể làm.
std::random_device
, time(NULL)
và địa chỉ chức năng, sau đó XORed với nhau để tạo ra một loại nguồn entropy nỗ lực tốt nhất.
std::random_device
đúng trên nền tảng mà bạn lập kế hoạch đang chạy chương trình của bạn vào, và cung cấp một hàm mà tạo ra một máy phát điện hạt giống ( seed11::make_seeded<std::mt19937>()
)