Bỏ qua để đến nội dung

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.

#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.

#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 Twister
  • std::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)
#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;
}
#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;
}

<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.

  • <random> (C++11) cung cấp cách sinh số ngẫu nhiên chất lượng cao, nên dùng thay cho rand() 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