Số ngẫu nhiên với <random>
Thư viện <random> (từ C++11) cung cấp cách sinh số ngẫu nhiên chất lượng cao, linh hoạt hơn nhiều so với hàm rand() cũ kế thừa từ C.
Vấn đề với rand() kiểu cũ
Phần tiêu đề “Vấn đề với rand() kiểu cũ”#include <cstdlib>#include <iostream>
int main() { std::cout << rand() % 100 << std::endl; // Cách cũ - chất lượng ngẫu nhiên thấp, phân bố không đều return 0;}rand() % n có xu hướng phân bố không đều (một số giá trị xuất hiện nhiều hơn giá trị khác) và chất lượng ngẫu nhiên kém hơn các thuật toán hiện đại - <random> khắc phục cả hai vấn đề này.
Sinh số nguyên ngẫu nhiên trong khoảng
Phần tiêu đề “Sinh số nguyên ngẫu nhiên trong khoảng”#include <random>#include <iostream>
int main() { std::random_device rd; // Nguồn "hạt giống" (seed) ngẫu nhiên thực sự từ hệ thống std::mt19937 gen(rd()); // Bộ sinh số ngẫu nhiên (Mersenne Twister) - chất lượng cao
std::uniform_int_distribution<int> dist(1, 100); // Phân bố đều trong khoảng [1, 100]
std::cout << dist(gen) << std::endl; // Một số ngẫu nhiên từ 1 đến 100
return 0;}std::random_device: cung cấp một seed ngẫu nhiên thực sự (dựa vào nguồn entropy của hệ điều hành)std::mt19937: bộ sinh số ngẫu nhiên giả (pseudo-random) chất lượng cao, dùng thuật toán Mersenne Twisterstd::uniform_int_distribution: định nghĩa khoảng giá trị và cách phân bố (ở đây là đều - mọi giá trị có xác suất xuất hiện như nhau)
Sinh nhiều số ngẫu nhiên
Phần tiêu đề “Sinh nhiều số ngẫu nhiên”#include <random>#include <iostream>
int main() { std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distribution<int> dist(1, 6); // Mô phỏng xúc xắc 6 mặt
for (int i = 0; i < 5; i++) { std::cout << dist(gen) << " "; } // Ví dụ: 3 6 1 4 2
return 0;}Số thực ngẫu nhiên
Phần tiêu đề “Số thực ngẫu nhiên”#include <random>#include <iostream>
int main() { std::random_device rd; std::mt19937 gen(rd()); std::uniform_real_distribution<double> dist(0.0, 1.0);
std::cout << dist(gen) << std::endl; // Một số thực ngẫu nhiên từ 0.0 đến 1.0
return 0;}Phân bố chuẩn (Normal Distribution)
Phần tiêu đề “Phân bố chuẩn (Normal Distribution)”<random> còn hỗ trợ nhiều kiểu phân bố khác ngoài phân bố đều, ví dụ phân bố chuẩn (Gaussian) - thường dùng trong mô phỏng khoa học, thống kê:
#include <random>#include <iostream>
int main() { std::random_device rd; std::mt19937 gen(rd()); std::normal_distribution<double> dist(0.0, 1.0); // Trung bình 0, độ lệch chuẩn 1
std::cout << dist(gen) << std::endl;
return 0;}Cố định seed để kết quả có thể lặp lại (hữu ích khi kiểm thử)
Phần tiêu đề “Cố định seed để kết quả có thể lặp lại (hữu ích khi kiểm thử)”#include <random>#include <iostream>
int main() { std::mt19937 gen(42); // Seed cố định = 42, thay vì random_device std::uniform_int_distribution<int> dist(1, 100);
std::cout << dist(gen) << std::endl; // Luôn cho cùng kết quả mỗi lần chạy chương trình
return 0;}Cố định seed rất hữu ích khi viết test tự động - đảm bảo kết quả “ngẫu nhiên” luôn giống nhau giữa các lần chạy để dễ so sánh và debug.
Tổng kết
Phần tiêu đề “Tổng kết”<random>(C++11) cung cấp cách sinh số ngẫu nhiên chất lượng cao, nên dùng thay chorand()kiểu cũ- Cần 3 thành phần: nguồn seed (
random_device), bộ sinh số (mt19937), và phân bố (uniform_int_distribution,normal_distribution…) - Dùng seed cố định khi cần kết quả “ngẫu nhiên” có thể lặp lại được, ví dụ trong kiểm thử tự động