True Random Number Generator (TRNG) – Tạo số random thật
Trong C++, để tạo số random thật (không thể biết trước) thì có thể sử dụng std::random_device trong thư viện random.
Hãy xem ví dụ bên dưới →
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <iostream> #include <random> int main() { std::random_device true_random_generator; std::uniform_int_distribution<int> int_distribution(0, 9); int actual_distribution[10] = { 0,0,0,0,0,0,0,0,0,0 }; for (int i = 0; i < 10000; i++) { int result = int_distribution(true_random_generator); actual_distribution[result]++; } for (int i = 0; i < 10; i++) { std::cout << actual_distribution[i] << " "; } return 0; } |
Mình giải thích qua một chút. Chương trình này thực hiện sinh số random kiểu int nằm trong khoảng 0 đến 9, sử dụng TRNG. Sau đó in ra kết quả để check xem mỗi số từ 0 đến 9 được sinh ra bao nhiêu lần. Khi chạy chương trình này thì mỗi lần chạy sẽ cho ra một kết quả khác nhau →
1 2 |
974 960 959 1048 1007 1038 994 1011 985 1024 # Chay lan 1 1003 986 968 1007 1015 1002 972 1032 996 1019 # Chay lan 2 |
Pseudo Random Number Generator (PRNG) – Tạo số random giả
Trong C++, để tạo số random giả thì có thể sử dụng std::default_random_engine trong thư viện random. Sở dĩ gọi là số random giả là vì kết quả của PRNG là một số trông có vẻ random nhưng thực ra không phải là random, nó là kết quả xác định trước của thuật toán xác định nên hoàn toàn có thể tái hiện lại nếu biết trạng thái của PRNG.
Ví dụ →
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <iostream> #include <random> int main() { std::default_random_engine pseudo_random_generator; std::uniform_int_distribution<int> int_distribution(0, 9); int actual_distribution[10] = { 0,0,0,0,0,0,0,0,0,0 }; for (int i = 0; i < 10000; i++) { int result = int_distribution(pseudo_random_generator); actual_distribution[result]++; } for (int i = 0; i <= 9; i++) { std::cout << actual_distribution[i] << " "; } return 0; } |
Cũng giống như chương trình bên trên, chương trình này thực hiện sinh số random kiểu int nằm trong khoảng 0 đến 9, sử dụng PRNG. Sau đó in ra kết quả để check xem mỗi số từ 0 đến 9 được sinh ra bao nhiêu lần. Tuy nhiên điểm khác biệt ở đây là khi chạy chương trình này thì các lần chạy đều cho ra một kết quả giống nhau →
1 2 |
1006 982 1042 997 1020 1063 1020 923 965 982 # Chay lan 1 1006 982 1042 997 1020 1063 1020 923 965 982 # Chay lan 2 |
Để có thể cho ra kết quả khác nhau với mỗi lần chạy thì cần khởi tạo giá trị cho biến pseudo_random_generator khách nhau với mỗi lần chạy (giá trị này gọi là seed). Thông thường người ta hay sử dụng thời gian hiện tại truyền vào làm giá trị seed ban đầu cho pseudo_random_generator . Ví dụ →
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include <iostream> #include <random> #include <chrono> using namespace std::chrono; int main() { time_t currentTime = system_clock::to_time_t(system_clock::now()); std::default_random_engine pseudo_random_generator(currentTime); std::uniform_int_distribution<int> int_distribution(0, 9); int actual_distribution[10] = { 0,0,0,0,0,0,0,0,0,0 }; for (int i = 0; i < 10000; i++) { int result = int_distribution(pseudo_random_generator); actual_distribution[result]++; } for (int i = 0; i <= 9; i++) { std::cout << actual_distribution[i] << " "; } return 0; } |
1 2 3 |
968 977 987 1000 1046 1041 1018 964 1015 984 # Chay lan 1 1086 1022 1012 951 973 1005 965 946 1015 1025 # Chay lan 2 1024 983 1010 992 1035 978 985 967 968 1058 # Chay lan 3 |
Recap
Trên đây mình chỉ giởi thiệu 2 phương pháp sử dụng thư viện chuẩn của C++. Ngoài ra các bạn cũng có thể sử dụng thư viện của C, đó làm hàm rand() trong stdlib.h (hoặc cstdlib). Hoặc trên Linux cũng có thể sử dụng file /dev/urandom. Tuy nhiên với các hệ thống đề cao tính portable (khả năng trên cùng một source code có thể build chương trình chạy được trên các platform, hoặc OS khác nhau mà không cần sửa hoặc sửa rất ít) thì các bạn nên sử dụng thư viện chuẩn của C/C++ bất cứ khi nào có thể.
— Phạm Minh Tuấn (Shun) —