Tạo số ngẫu nhiên trong C ++ 11: Làm thế nào để tạo, nó hoạt động như thế nào? [đóng cửa]


102

Gần đây tôi đã tìm ra cách mới để tạo số ngẫu nhiên trong C ++ 11, nhưng không thể hiểu được các bài báo mà tôi đã đọc về nó ( động cơ đó là gì , thuật ngữ toán học như phân phối , "nơi tất cả các số nguyên được tạo ra đều có khả năng như nhau ").

Vì vậy, bất cứ ai có thể xin vui lòng giải thích

  • họ là ai?
  • chúng có nghĩa là gì?
  • làm thế nào để tạo ra?
  • họ làm việc như thế nào?
  • Vân vân

Bạn có thể gọi tất cả trong một Câu hỏi thường gặp về tạo số ngẫu nhiên.


6
Hỏi về RNG mà không biết phân phối là gì giống như hỏi về trình phân tích cú pháp biểu thức mà không biết biểu thức là gì ... Thư viện RNG trong C ++ 11 hướng đến những người biết một số thống kê và có nhu cầu lớn hơn phân phối phẳng được tạo bởi rand, bạn nên xem nhanh wikipedia để biết một số khái niệm cơ bản về thống kê và RNG, nếu không sẽ rất khó để giải thích cho bạn cơ sở lý luận <random>và cách sử dụng các phần khác nhau của nó.
Matteo Italia

26
@Matteo: Khó. Một đứa trẻ có thể hiểu khái niệm rằng một con súc sắc tạo ra các số ngẫu nhiên mà không cần hiểu phân phối là gì.
Benjamin Lindley

3
@Benjamin: và đó là nơi sự hiểu biết của anh ấy dừng lại, đó mới chỉ là bước đầu tiên (các động cơ), và thậm chí không hiểu tại sao điều quan trọng là chúng phải tạo ra một phân phối phẳng. Tất cả phần còn lại của thư viện vẫn là một bí ẩn nếu không hiểu về phân phối và các khái niệm thống kê khác.
Matteo Italia

Câu trả lời:


142

Câu hỏi quá rộng để có một câu trả lời đầy đủ, nhưng hãy để tôi chọn ra một vài điểm thú vị:

Tại sao "có khả năng như nhau"

Giả sử bạn có một trình tạo số ngẫu nhiên đơn giản tạo ra các số 0, 1, ..., 10 mỗi số với xác suất bằng nhau (hãy nghĩ về điều này là cổ điển rand()). Bây giờ bạn muốn một số ngẫu nhiên trong phạm vi 0, 1, 2, mỗi số có xác suất bằng nhau. Phản ứng giật đầu gối của bạn sẽ xảy ra rand() % 3. Nhưng chờ đợi, phần còn lại 0 và 1 xảy ra thường xuyên hơn phần còn lại 2, vì vậy điều này không chính xác!

Đây là lý do tại sao chúng ta cần các phân phối thích hợp , lấy nguồn các số nguyên ngẫu nhiên đồng nhất và biến chúng thành phân phối mong muốn của chúng ta, như Uniform[0,2]trong ví dụ. Tốt nhất hãy để nó vào một thư viện tốt!

Động cơ

Do đó, trung tâm của tất cả sự ngẫu nhiên là một trình tạo số giả ngẫu nhiên tốt tạo ra một chuỗi các số phân bố đồng đều trong một khoảng thời gian nhất định và lý tưởng là có một khoảng thời gian rất dài. Việc triển khai tiêu chuẩn rand()thường không phải là tốt nhất, và do đó, thật tốt khi có sự lựa chọn. Linear-congruential và Mersenne twister là hai lựa chọn tốt (LG thực tế cũng thường được sử dụng rand()); một lần nữa, thật tốt khi để thư viện xử lý việc đó.

Làm thế nào nó hoạt động

Dễ dàng: đầu tiên, thiết lập một động cơ và gieo nó. Hạt giống hoàn toàn xác định toàn bộ chuỗi số "ngẫu nhiên", vì vậy a) sử dụng một số khác (ví dụ lấy từ /dev/urandom) mỗi lần và b) lưu trữ hạt giống nếu bạn muốn tạo lại một chuỗi các lựa chọn ngẫu nhiên.

#include <random>

typedef std::mt19937 MyRNG;  // the Mersenne Twister with a popular choice of parameters
uint32_t seed_val;           // populate somehow

MyRNG rng;                   // e.g. keep one global instance (per thread)

void initialize()
{
  rng.seed(seed_val);
}

Bây giờ chúng ta có thể tạo các bản phân phối:

std::uniform_int_distribution<uint32_t> uint_dist;         // by default range [0, MAX]
std::uniform_int_distribution<uint32_t> uint_dist10(0,10); // range [0,10]
std::normal_distribution<double> normal_dist(mean, stddeviation);  // N(mean, stddeviation)

... Và sử dụng công cụ để tạo ra các số ngẫu nhiên!

while (true)
{
  std::cout << uint_dist(rng) << " "
            << uint_dist10(rng) << " "
            << normal_dist(rng) << std::endl;

}

Đồng tiền

Một lý do quan trọng hơn để thích <random>hơn so với truyền thống rand()là giờ đây nó đã rất rõ ràng và rõ ràng về cách tạo an toàn cho luồng tạo số ngẫu nhiên: Cung cấp cho mỗi luồng một công cụ cục bộ luồng của riêng nó, được gieo trên hạt cục bộ của luồng hoặc đồng bộ hóa quyền truy cập đến đối tượng động cơ.

Misc

  • Một bài báo thú vị về TR1 ngẫu nhiên trên codeguru.
  • Wikipedia có một bản tóm tắt tốt (cảm ơn, @Justin).
  • Về nguyên tắc, mỗi động cơ phải result_typegõ a , là loại tích phân chính xác để sử dụng cho hạt giống. Tôi nghĩ rằng tôi đã có một thi buggy lần mà buộc tôi phải buộc các hạt giống cho std::mt19937đến uint32_ttrên x64, cuối cùng này cần được cố định và bạn có thể nói MyRNG::result_type seed_valvà do đó làm cho động cơ rất dễ dàng thay thế.

Một lần nữa, Kerrek đánh bại tôi với một câu trả lời hay hơn nhiều so với câu trả lời mà tôi đang làm. +1
Justin ᚅᚔᚈᚄᚒᚔ

@Justin: Tôi chắc chắn rằng tôi đã bỏ lỡ rất nhiều thứ, vui lòng bổ sung thêm các khía cạnh khác cho chủ đề này! :-)
Kerrek SB

13
Đối với các "cư bằng cách nào đó" một phần, tôi nghĩ std::random_devicelà đáng nói hơn là/dev/urandom
Cubbi

2
Một ví dụ về std::random_devicecó thể được tìm thấy ở đây .
WKS

1
Mã trong bài viết Wikipedia có lỗi. random và random2 là giống hệt nhau. Từ các nhận xét trong đoạn mã, rõ ràng là tác giả không hiểu cách sử dụng các tính năng trong <random>.
user515430

3

Một bộ tạo số ngẫu nhiên là một phương trình, cho trước một số, sẽ cung cấp cho bạn một số mới. Thông thường, bạn cung cấp số đầu tiên hoặc số của nó được lấy từ một cái gì đó như giờ hệ thống.

Mỗi khi bạn yêu cầu một số mới, nó sẽ sử dụng số trước đó để thực hiện phương trình.

Một bộ tạo số ngẫu nhiên không được coi là tốt lắm nếu nó có xu hướng tạo ra cùng một số thường xuyên hơn các số khác. tức là nếu bạn muốn một số ngẫu nhiên từ một đến 5 và bạn có phân phối số này:

  • 1: 1%
  • 2: 80%
  • 3: 5%
  • 4: 5%
  • 5: 9%

2 được tạo FAR thường xuyên hơn bất kỳ số nào khác, vì vậy nó có nhiều khả năng được tạo ra hơn các số khác. Nếu tất cả các số đều giống nhau, bạn sẽ có 20% cơ hội nhận được mỗi số mỗi lần. Nói cách khác, sự phân bổ trên là rất không đồng đều vì 2 là ưu ái. Một phân phối với tất cả 20% sẽ là đồng đều.

Thông thường, nếu bạn muốn một số ngẫu nhiên thực sự, bạn sẽ lấy dữ liệu từ một cái gì đó như thời tiết hoặc một số nguồn tự nhiên khác chứ không phải là một bộ tạo số ngẫu nhiên.


8
Hầu hết các trình tạo số ngẫu nhiên đều tạo ra các phân phối đồng đều tốt. Chúng không phải là ngẫu nhiên; vấn đề là chúng được tính toán và do đó bạn có thể đoán số tiếp theo cho đủ số trong dãy (thực tế này làm cho chúng kém an toàn khi yêu cầu các số thực sự ngẫu nhiên). Đối với trò chơi và nội dung, bạn sẽ ổn.
Martin York

5
Tôi khá chắc chắn OP đang yêu cầu thông tin cụ thể về các cơ sở được cung cấp trong tiêu đề C ++ <random>. Câu trả lời này thậm chí không đề cập đến lập trình chứ đừng nói đến C ++.
Benjamin Lindley

1
@Martin: Bảo mật không nhất thiết yêu cầu nguồn các số thực sự ngẫu nhiên. AES trong chế độ bộ đếm (ví dụ) có thể hoạt động khá tốt mặc dù nó mang tính xác định. Nó yêu cầu một lượng entropy hợp lý trong khóa, nhưng không phải là bất kỳ sự ngẫu nhiên thực sự nào.
Jerry Coffin

@Benjamin Lindley: Đừng bận tâm. Chỉ cần đọc lại và nhận ra mình đã sai.
N_A
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.