[2026] C++ random numbers | Complete Guide to the C++11 random library

[2026] C++ random numbers | Complete Guide to the C++11 random library

이 글의 핵심

Why rand() is problematic, how to use random_device, mt19937, and distributions in C++11, with dice simulations, shuffling, weighted picks, seeding, and performance notes.

Problems with rand()

아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// ❌ Legacy style
srand(time(0));
int x = rand() % 100;  // 0-99
// Issues:
// 1. Not a uniform distribution
// 2. Low statistical quality
// 3. Not thread-safe

Modern random numbers (C++11)

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <random>
int main() {
    // Seed
    random_device rd;
    
    // Engine
    mt19937 gen(rd());
    
    // Distribution
    uniform_int_distribution<> dis(1, 100);
    
    // Generate
    for (int i = 0; i < 10; i++) {
        cout << dis(gen) << " ";
    }
}

Random engines

아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// Mersenne Twister (recommended)
mt19937 gen32;      // 32-bit
mt19937_64 gen64;   // 64-bit
// Linear congruential (fast, lower quality)
minstd_rand gen;
// Subtract-with-carry
ranlux24 gen;

Distributions

Uniform

아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// Integers
uniform_int_distribution<> intDis(1, 6);  // dice
int dice = intDis(gen);
// Reals
uniform_real_distribution<> realDis(0.0, 1.0);
double x = realDis(gen);

Normal

normal_distribution<> normalDis(100.0, 15.0);  // mean 100, stddev 15
double iq = normalDis(gen);

Other distributions

다음은 cpp를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// Bernoulli (true/false)
bernoulli_distribution coinFlip(0.5);  // 50%
bool result = coinFlip(gen);
// Binomial
binomial_distribution<> binDis(10, 0.5);
int heads = binDis(gen);
// Poisson
poisson_distribution<> poisDis(4.0);
int events = poisDis(gen);
// Exponential
exponential_distribution<> expDis(1.0);
double time = expDis(gen);

Practical examples

Example 1: Dice histogram

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <random>
#include <map>
int main() {
    random_device rd;
    mt19937 gen(rd());
    uniform_int_distribution<> dice(1, 6);
    
    map<int, int> histogram;
    
    // Roll 10000 times
    for (int i = 0; i < 10000; i++) {
        int roll = dice(gen);
        histogram[roll]++;
    }
    
    // Print histogram
    for (const auto& [value, count] : histogram) {
        cout << value << ": " << string(count / 100, '*') << endl;
    }
}

Example 2: Random string

다음은 cpp를 활용한 상세한 구현 코드입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

string generateRandomString(size_t length) {
    static random_device rd;
    static mt19937 gen(rd());
    static uniform_int_distribution<> dis(0, 61);
    
    const string chars = 
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";
    
    string result;
    for (size_t i = 0; i < length; i++) {
        result += chars[dis(gen)];
    }
    
    return result;
}
int main() {
    cout << generateRandomString(10) << endl;
    cout << generateRandomString(20) << endl;
}

Example 3: Shuffle

아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <algorithm>
int main() {
    vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    
    random_device rd;
    mt19937 gen(rd());
    
    shuffle(v.begin(), v.end(), gen);
    
    for (int x : v) {
        cout << x << " ";
    }
}

Example 4: Weighted discrete choice

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <random>
int main() {
    random_device rd;
    mt19937 gen(rd());
    
    // Weights: 10%, 30%, 60%
    discrete_distribution<> dis({10, 30, 60});
    
    map<int, int> histogram;
    
    for (int i = 0; i < 10000; i++) {
        int choice = dis(gen);
        histogram[choice]++;
    }
    
    for (const auto& [choice, count] : histogram) {
        cout << "choice " << choice << ": " << count << " times" << endl;
    }
}

Seeding

아래 코드는 cpp를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// Time-based (not reproducible)
mt19937 gen1(time(0));
// random_device (recommended for non-fixed seeds)
random_device rd;
mt19937 gen2(rd());
// Fixed seed (reproducible)
mt19937 gen3(12345);
// Seed sequence
seed_seq seq{1, 2, 3, 4, 5};
mt19937 gen4(seq);

Common pitfalls

Pitfall 1: Creating an engine every call

다음은 cpp를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ❌ Inefficient
int getRandom() {
    random_device rd;
    mt19937 gen(rd());  // created every time (slow)
    uniform_int_distribution<> dis(1, 100);
    return dis(gen);
}
// ✅ static storage
int getRandom() {
    static random_device rd;
    static mt19937 gen(rd());
    static uniform_int_distribution<> dis(1, 100);
    return dis(gen);
}

Pitfall 2: Reseeding inside a loop

아래 코드는 cpp를 사용한 구현 예제입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ❌ Same short sequence each iteration
for (int i = 0; i < 10; i++) {
    mt19937 gen(12345);  // always the same seed
    cout << gen() << endl;
}
// ✅ Reuse one engine
mt19937 gen(12345);
for (int i = 0; i < 10; i++) {
    cout << gen() << endl;
}

Pitfall 3: Biased ranges with rand()

아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// ❌ Biased
int x = rand() % 100;  // not uniform
// ✅ Uniform distribution
uniform_int_distribution<> dis(0, 99);
int x = dis(gen);

Performance comparison

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <chrono>
int main() {
    const int N = 10000000;
    
    // rand()
    srand(time(0));
    auto start = chrono::high_resolution_clock::now();
    for (int i = 0; i < N; i++) {
        int x = rand();
    }
    auto end = chrono::high_resolution_clock::now();
    cout << "rand(): " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << "ms" << endl;
    
    // mt19937
    random_device rd;
    mt19937 gen(rd());
    start = chrono::high_resolution_clock::now();
    for (int i = 0; i < N; i++) {
        int x = gen();
    }
    end = chrono::high_resolution_clock::now();
    cout << "mt19937: " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << "ms" << endl;
}

FAQ

Q1: rand() vs the random library?

A:

  • rand(): legacy, poor quality.
  • random: modern, higher quality, more flexible.

Q2: Must I always use random_device?

A: Use it for seeding. Generate numbers with an engine.

Q3: Which engine should I use?

A: In most cases mt19937 is a solid default.

Q4: How do I get reproducible sequences?

A: Use a fixed seed.

Q5: Is it thread-safe?

A: Give each thread its own engine (and distribution if needed).

Q6: Learning resources?

A:

  • cppreference.com
  • The C++ Standard Library (Nicolai Josuttis)
  • Effective Modern C++

Practical tips

Debugging

  • Fix compiler warnings first.
  • Reproduce with a small test case.

Performance

  • Do not optimize without profiling.
  • Define measurable goals first.

Code review

  • Catch common review issues early.
  • Follow team conventions.

Production checklist

Before coding

  • Is this the right approach?
  • Can teammates maintain it?
  • Does it meet performance needs?

While coding

  • Warnings cleared?
  • Edge cases covered?
  • Error handling adequate?

At review

  • Intent clear?
  • Tests sufficient?
  • Documentation where needed?

Keywords

C++, random, C++11, mt19937, uniform distribution

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3