Xác nhận rand() % n
là ít hơn lý tưởng
Làm rand() % n
có một phân phối không đồng đều. Bạn sẽ nhận được số lượng giá trị nhất định không tương xứng vì số lượng giá trị không phải là bội số của 20
Tiếp theo, rand()
thường là một trình tạo đồng quy tuyến tính (có nhiều công cụ khác , chỉ có điều này là khả năng được triển khai nhất - và với ít hơn các tham số lý tưởng (có nhiều cách để chọn tham số)). Vấn đề lớn nhất với điều này là thường các bit thấp trong đó (các bit bạn nhận được với % 20
biểu thức kiểu) không phải là ngẫu nhiên. Tôi nhớ lại một rand()
từ năm trước mà các bit thấp nhất xen kẽ từ 1
đến 0
với mỗi cuộc gọi đến rand()
- đó là không phải là rất ngẫu nhiên.
Từ trang rand (3) man:
Các phiên bản của rand () và srand () trong Thư viện Linux C sử dụng giống nhau
trình tạo số ngẫu nhiên là ngẫu nhiên () và srandom (), vì vậy thứ tự thấp hơn
các bit nên ngẫu nhiên như các bit bậc cao hơn. Tuy nhiên, về già
triển khai rand () và trên các triển khai hiện tại khác nhau
các hệ thống, các bit bậc thấp ít ngẫu nhiên hơn nhiều so với các bit cao hơn
bit thứ tự. Không sử dụng chức năng này trong các ứng dụng dự định là
xách tay khi cần sự ngẫu nhiên tốt.
Điều này có thể đã bị rớt xuống lịch sử, nhưng hoàn toàn có khả năng bạn vẫn có một triển khai rand () kém ở đâu đó trong ngăn xếp. Trong trường hợp đó, nó vẫn còn khá áp dụng.
Điều cần làm là thực sự sử dụng một thư viện số ngẫu nhiên tốt (cung cấp các số ngẫu nhiên tốt) và sau đó yêu cầu các số ngẫu nhiên trong phạm vi bạn muốn.
Một ví dụ về bit số ngẫu nhiên tốt (từ 13:00 trong video được liên kết)
#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;
}
So sánh điều này với:
#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");
}
Chạy cả hai chương trình này và so sánh tần suất các số nhất định xuất hiện (hoặc không xuất hiện) trong đầu ra đó.
Video liên quan: rand () được coi là có hại
Một số khía cạnh lịch sử của rand () gây ra lỗi trong Nethack mà người ta nên xem và xem xét trong các triển khai của chính mình:
Vấn đề NNGack RNG
Rand () là một hàm rất cơ bản để tạo số ngẫu nhiên của Nethack. Cách Nethack sử dụng nó là lỗi hoặc có thể lập luận rằng lrand48 () tạo ra các số giả ngẫu nhiên tào lao. (Tuy nhiên, lrand48 () là một hàm thư viện sử dụng phương thức PRNG được xác định và bất kỳ chương trình nào sử dụng nó đều phải tính đến các điểm yếu của phương thức đó.)
Lỗi là Nethack dựa (đôi khi chỉ như trường hợp trong rn (2)) trên các bit thấp hơn của kết quả từ lrand48 (). Bởi vì điều này, RNG trong toàn bộ trò chơi hoạt động xấu. Điều này đặc biệt đáng chú ý trước khi hành động của người dùng giới thiệu tính ngẫu nhiên hơn nữa, tức là trong việc tạo nhân vật và tạo cấp độ đầu tiên.
Mặc dù ở trên là từ năm 2003, nhưng vẫn nên ghi nhớ vì có thể không phải tất cả các hệ thống chạy trò chơi dự định của bạn sẽ là một hệ thống Linux cập nhật với chức năng rand () tốt.
Nếu bạn chỉ làm điều này cho chính mình, bạn có thể kiểm tra trình tạo số ngẫu nhiên của bạn tốt như thế nào bằng cách viết một số mã và kiểm tra đầu ra với ent .
Về tính chất của số ngẫu nhiên
Có những cách hiểu khác về 'ngẫu nhiên' không chính xác ngẫu nhiên. Trong một luồng dữ liệu ngẫu nhiên, hoàn toàn có thể nhận được cùng một số hai lần. Nếu bạn lật một đồng xu (ngẫu nhiên), hoàn toàn có thể có được hai đầu liên tiếp. Hoặc ném xúc xắc hai lần và nhận được cùng một số hai lần liên tiếp. Hoặc quay một bánh xe roulette và nhận được cùng một số hai lần ở đó.
Sự phân bố số
Khi phát danh sách bài hát, mọi người mong đợi 'ngẫu nhiên' có nghĩa là cùng một bài hát hoặc nghệ sĩ sẽ không được phát lần thứ hai liên tiếp. Có một danh sách phát phát The Beatles hai lần liên tiếp được coi là "không ngẫu nhiên" (mặc dù đó là ngẫu nhiên). Nhận thức cho một danh sách chơi gồm bốn bài hát đã chơi tổng cộng tám lần:
1 3 2 4 1 2 4 3
là 'ngẫu nhiên' hơn:
1 3 3 2 1 4 4 2
Thêm về điều này cho 'xáo trộn' các bài hát: Làm thế nào để xáo trộn các bài hát?
Trên các giá trị lặp lại
Nếu bạn không muốn lặp lại các giá trị, có một cách tiếp cận khác cần được xem xét. Tạo tất cả các giá trị có thể, và xáo trộn chúng.
Nếu bạn đang gọi rand()
(hoặc bất kỳ trình tạo số ngẫu nhiên nào khác), bạn đang gọi nó với sự thay thế. Bạn luôn có thể nhận được cùng một số hai lần. Một tùy chọn là tung ra các giá trị nhiều lần cho đến khi bạn chọn một giá trị đáp ứng yêu cầu của bạn. Tôi sẽ chỉ ra rằng điều này có thời gian chạy không xác định và có thể bạn có thể thấy mình trong tình huống có một vòng lặp vô hạn trừ khi bạn bắt đầu thực hiện theo dõi ngược phức tạp hơn.
Liệt kê và chọn
Một tùy chọn khác là tạo danh sách tất cả các trạng thái hợp lệ có thể và sau đó chọn một yếu tố ngẫu nhiên từ danh sách đó. Tìm tất cả các điểm trống (đáp ứng một số quy tắc) trong phòng và sau đó chọn một điểm ngẫu nhiên từ danh sách đó. Và sau đó làm đi làm lại nhiều lần cho đến khi bạn hoàn thành.
Xáo trộn
Cách tiếp cận khác là xáo trộn như thể đó là một cỗ bài. Bắt đầu với tất cả các điểm trống trong phòng và sau đó bắt đầu chỉ định chúng bằng cách xử lý các điểm trống, từng điểm một, cho từng quy tắc / quy trình yêu cầu một điểm trống. Bạn đã hoàn thành khi bạn hết thẻ hoặc mọi thứ ngừng yêu cầu chúng.