Những công cụ số ngẫu nhiên nào của <Random> nên thực sự sử dụng trong thực tế? std :: mt19937?


21

Giả sử bạn muốn sử dụng <random>các tiện ích C ++ trong một chương trình thực tế (đối với một số định nghĩa về "thực tế" - các ràng buộc ở đây là một phần của câu hỏi này). Bạn đã có mã đại khái như thế này:

int main(int argc, char **argv) {
    int seed = get_user_provided_seed_value(argc, argv);
    if (seed == 0) seed = std::random_device()();
    ENGINE g(seed);  // TODO: proper seeding?
    go_on_and_use(g);
}

Câu hỏi của tôi là, bạn nên sử dụng loại ENGINEnào?

  • Tôi thường nói std::mt19937vì nó gõ nhanh và nhận dạng tên. Nhưng ngày nay, dường như mọi người đều nói rằng Mersenne Twister rất nặng và không thân thiện với bộ nhớ cache và thậm chí không vượt qua tất cả các bài kiểm tra thống kê mà người khác làm.

  • Tôi muốn nói std::default_random_enginevì đó là "mặc định" rõ ràng. Nhưng tôi không biết nếu nó thay đổi từ nền tảng này sang nền tảng khác tôi không biết liệu nó có tốt về mặt thống kê hay không.

  • Kể từ khi tất cả mọi người trên một nền tảng 64-bit những ngày này, chúng ta nên ít nhất được sử dụng std::mt19937_64trên std::mt19937?

  • Tôi muốn nói pcg64hoặc xoroshiro128bởi vì họ có vẻ được tôn trọng và nhẹ, nhưng họ hoàn toàn không tồn <random>tại.

  • Tôi không biết gì về minstd_rand, minstd_rand0, ranlux24, knuth_b, vv - chắc chắn họ phải có tốt cho cái gì?

Rõ ràng có một số hạn chế cạnh tranh ở đây.

  • Sức mạnh của động cơ. ( <random>không có PRNG mã hóa mạnh, nhưng vẫn có một số PRNG được tiêu chuẩn hóa "yếu" hơn các loại khác, phải không?)

  • sizeof động cơ.

  • Tốc độ của nó operator().

  • Dễ gieo hạt. mt19937nổi tiếng là khó để gieo hạt đúng cách vì nó có quá nhiều trạng thái để khởi tạo.

  • Tính di động giữa các nhà cung cấp thư viện. Nếu một nhà cung cấp foo_enginetạo ra các số khác nhau từ một nhà cung cấp khác foo_engine, điều đó không tốt cho một số ứng dụng. (Hy vọng rằng quy tắc này không có gì ngoại trừ có thể default_random_engine.)

Cân nhắc tất cả những ràng buộc này một cách tốt nhất có thể, bạn sẽ nói gì là câu trả lời "thực hành tốt nhất trong thư viện tiêu chuẩn" cuối cùng? Tôi chỉ nên tiếp tục sử dụng std::mt19937, hoặc những gì?


2
Đến điểm cuối cùng của bạn, tất cả các bộ điều hợp động cơ tiêu chuẩn được chỉ định để trả về một giá trị cụ thể trên một lệnh gọi liên tiếp cụ thể của cấu trúc mặc định được xây dựng, vì vậy chúng phải có thể mang theo được.
1201 Chương trình Chương trình

Câu trả lời:


15

Tham khảo C ++ liệt kê tất cả các công cụ ngẫu nhiên hiện đang được cung cấp bởi C ++. Tuy nhiên, việc lựa chọn các động cơ để lại rất nhiều mong muốn (ví dụ, xem danh sách các máy phát ngẫu nhiên chất lượng cao của tôi ). Ví dụ:

  • default_random_engine được xác định theo triển khai, vì vậy không biết liệu động cơ có lỗi thống kê mà ứng dụng có thể quan tâm hay không.
  • linear_congruential_enginethực hiện các máy phát đồng quy tuyến tính. Tuy nhiên, chúng có xu hướng có chất lượng kém trừ khi mô đun là số nguyên tố và rất lớn (ít nhất là 64 bit). Ngoài ra, họ không thể thừa nhận nhiều hạt giống hơn mô đun của họ.
  • minstd_rand0minstd_randchỉ thừa nhận khoảng 2 ^ 31 hạt giống. knuth_bkết thúc tốt đẹp minstd_rand0và thực hiện một shuffle Bays của Durham.
  • mt19937mt19937_64có thể thừa nhận nhiều hạt giống hơn nếu chúng được khởi tạo tốt hơn (ví dụ: bằng cách khởi tạo một std::seed_seqvới nhiều đầu ra random_device, không chỉ một), nhưng chúng sử dụng khoảng 2500 byte trạng thái.
  • ranlux24ranlux48sử dụng khoảng 577 bit trạng thái nhưng chúng chậm (chúng hoạt động bằng cách giữ một số và loại bỏ các đầu ra giả ngẫu nhiên khác).

Tuy nhiên, C ++ cũng có hai công cụ bao bọc một công cụ khác để có khả năng cải thiện các tính chất ngẫu nhiên của nó:

  • discard_block_engine loại bỏ một số đầu ra của một công cụ ngẫu nhiên nhất định.
  • shuffle_order_engine thực hiện một shuffle Bays của Durham của một công cụ ngẫu nhiên nhất định.

Ví dụ, nó có thể, ví dụ, để có một shuffle Vịnh-Durham của mt19937, ranlux24hoặc tùy chỉnh linear_congruential_enginevới shuffle_order_engine. Có lẽ động cơ bọc có chất lượng tốt hơn so với bản gốc. Tuy nhiên, thật khó để dự đoán chất lượng thống kê của động cơ mới mà không kiểm tra nó .

Do đó, trong khi chờ các thử nghiệm như vậy, có vẻ như đó mt19937là công cụ thiết thực nhất trong tiêu chuẩn C ++ hiện nay. Tuy nhiên, tôi biết rằng có ít nhất một đề xuất để thêm một công cụ số ngẫu nhiên khác vào các phiên bản tương lai của C ++ (xem bài viết C ++ P2075 ).


1

Theo tài liệu tham khảo C ++ , default_random_engine:

Là lựa chọn của trình triển khai thư viện cung cấp ít nhất hành vi động cơ có thể chấp nhận được cho việc sử dụng tương đối ngẫu nhiên, thiếu kinh nghiệm và / hoặc nhẹ.

Vì vậy, cho sử dụng nhẹ bạn không cần phải lo lắng về bất cứ điều gì, hạt giống default_random_enginevới Epoch Time (time(0))và đó sẽ là đủ tốt;)


Tôi tin rằng vấn đề ở đây là tính di động. Mặc dù mặc định có thể là một công cụ hoạt động tốt, nhưng nó có thể không thể tái tạo trên nền tảng khác.
bremen_matt

@bremen_matt Hmm ... Chà, tại sao chúng ta cần sao chép một số "ngẫu nhiên"?
Farbod Ahmadian

2
Kiểm tra. Đối với mục đích thử nghiệm, bạn cần đầu vào có thể tái tạo. Đồng thời, bạn có thể muốn hoặc cần những đầu vào đó là ngẫu nhiên. Ví dụ, hầu hết các thuật toán học máy đều cho rằng các tham số được khởi tạo ngẫu nhiên. Ransac, CNN, DNN, ... nhiều thuật toán yêu cầu tham số ngẫu nhiên.
bremen_matt
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.