Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C++

Sinh số ngẫu nhiên với thư viện C++11

C++11 cung cấp thư viện <random> hiện đại, thay thế hoàn toàn rand()/srand() cũ. Thư viện này tách biệt engine (bộ sinh bit) và distribution (phân phối thống kê).

Các thành phần chính

LoạiVí dụMô tả
Enginemt19937, mt19937_64Mersenne Twister - nhanh, chất lượng cao, chu kỳ 2¹⁹⁹³⁷-1
Enginerandom_deviceNguồn entropy thật (hardware), dùng để seed
Distributionuniform_int_distributionSố nguyên phân phối đều
Distributionuniform_real_distributionSố thực phân phối đều
Distributionnormal_distributionPhân phối chuẩn (Gaussian)

Ví dụ: Số thực ngẫu nhiên [20.0, 22.0]

#include <random>
#include <iostream>

using namespace std;

int main() {
    // 1. Nguồn entropy để seed
    random_device rd;
    
    // 2. Engine: Mersenne Twister 32-bit
    mt19937 mt(rd());
    
    // 3. Distribution: Số thực đều [20, 22]
    uniform_real_distribution<double> dist(20.0, 22.0);
    
    // 4. Sinh 20 số
    for (int i = 0; i < 20; ++i) {
        cout << dist(mt) << endl;
    }
}

Kết quả mẫu

21.5311
21.7195
21.0961
21.9679
21.197
21.2989
20.6333
20.441
20.7124
20.2654
21.1877
20.4824
20.0575
20.9432
21.222
21.162
21.1029
20.2253
21.5669
20.3357

Ví dụ: Số nguyên ngẫu nhiên [1, 6] (tung xúc xắc)


#include <random>
#include <iostream>

int main() {
    random_device rd;
    mt19937 gen(rd());
    uniform_int_distribution<> die(1, 6);  // [1, 6]
    
    for (int i = 0; i < 10; ++i) {
        cout << die(gen) << " ";
    }
}

Ví dụ: Phân phối chuẩn (Normal/Gaussian)


#include <random>
#include <iostream>
#include <map>

int main() {
    random_device rd;
    mt19937 gen(rd());
    normal_distribution<> dist(5.0, 2.0);  // mean=5, stddev=2
    
    map<int, int> hist;
    for (int i = 0; i < 10000; ++i) {
        ++hist[static_cast<int>(dist(gen))];
    }
    
    for (auto [val, count] : hist) {
        cout << val << ": " << string(count / 200, '*') << endl;
    }
}

Best Practices

  1. Không tạo engine mới mỗi lần — tốn chi phí, giảm chất lượng ngẫu nhiên
  2. Dùng random_device để seed một lần — không seed bằng time(0)
  3. Thread-local engine cho multi-thread:

thread_local mt19937 gen(random_device{}());
uniform_int_distribution<> dist(1, 100);

int random_number() {
    return dist(gen);  // An toàn thread
}

So sánh nhanh

Đặc điểmrand()/srand()<random> (C++11)
Chất lượng ngẫu nhiênThấp (LCG)Cao (MT19937)
Phân phốiChỉ đều cơ bảnNhiều loại (normal, poisson...)
Thread safetyKhôngCó (thread_local engine)
Seedtime(0) - yếurandom_device - mạnh
Type safetyKhôngCó (template)

Kết luận

Luôn dùng <random> cho code C++11 trở lên. Chỉ dùng rand() cho code legacy hoặc bài tập đơn giản.