C++ std::distribution | Probability distributions in the random header

C++ std::distribution | Probability distributions in the random header

이 글의 핵심

Practical guide to std::uniform_int_distribution, normal_distribution, and related types: when to pick each, how they pair with engines, and common pitfalls.

What is a distribution?

Probability distributions (C++11)

#include <random>

std::mt19937 gen{std::random_device{}()};

// Uniform distribution
std::uniform_int_distribution<> uniform{1, 6};
int dice = uniform(gen);

// Normal distribution
std::normal_distribution<> normal{0.0, 1.0};
double value = normal(gen);

Uniform distributions

#include <random>

std::mt19937 gen{std::random_device{}()};

// Integers
std::uniform_int_distribution<> intDist{0, 99};
int randomInt = intDist(gen);

// Reals
std::uniform_real_distribution<> realDist{0.0, 1.0};
double randomDouble = realDist(gen);

Practical examples

Example 1: Normal distribution histogram

#include <random>
#include <map>

int main() {
    std::mt19937 gen{std::random_device{}()};
    std::normal_distribution<> dist{100.0, 15.0};  // mean 100, stddev 15
    
    std::map<int, int> histogram;
    
    for (int i = 0; i < 10000; ++i) {
        double value = dist(gen);
        ++histogram[static_cast<int>(std::round(value / 10) * 10)];
    }
    
    for (const auto& [value, count] : histogram) {
        std::cout << value << ": " << std::string(count / 100, '*') << std::endl;
    }
}

Example 2: Bernoulli distribution

#include <random>

int main() {
    std::mt19937 gen{std::random_device{}()};
    std::bernoulli_distribution dist{0.7};  // 70% probability
    
    int success = 0;
    for (int i = 0; i < 100; ++i) {
        if (dist(gen)) {
            ++success;
        }
    }
    
    std::cout << "Successes: " << success << "/100" << std::endl;
}

Example 3: Binomial distribution

#include <random>

int main() {
    std::mt19937 gen{std::random_device{}()};
    std::binomial_distribution<> dist{10, 0.5};  // 10 trials, 50% each
    
    for (int i = 0; i < 10; ++i) {
        int successes = dist(gen);
        std::cout << "Success count: " << successes << std::endl;
    }
}

Example 4: Weighted discrete choice

#include <random>
#include <vector>
#include <string>
#include <map>

int main() {
    std::vector<std::string> items = {"common", "uncommon", "rare", "epic", "legendary"};
    std::vector<double> weights = {0.5, 0.3, 0.15, 0.04, 0.01};
    
    std::mt19937 gen{std::random_device{}()};
    std::discrete_distribution<> dist{weights.begin(), weights.end()};
    
    std::map<std::string, int> drops;
    
    for (int i = 0; i < 1000; ++i) {
        int index = dist(gen);
        ++drops[items[index]];
    }
    
    for (const auto& [item, count] : drops) {
        std::cout << item << ": " << count << std::endl;
    }
}

Distribution families

// Uniform
std::uniform_int_distribution<>      // integers
std::uniform_real_distribution<>     // reals

// Bernoulli family
std::bernoulli_distribution          // bool
std::binomial_distribution<>         // binomial
std::geometric_distribution<>        // geometric

// Normal family
std::normal_distribution<>           // Gaussian
std::lognormal_distribution<>        // log-normal

// Poisson family
std::poisson_distribution<>          // Poisson
std::exponential_distribution<>      // exponential

// Sampling
std::discrete_distribution<>         // weighted index
std::piecewise_constant_distribution<>

Common pitfalls

Pitfall 1: Range semantics

// uniform_int_distribution: [a, b] inclusive
std::uniform_int_distribution<> intDist{0, 9};  // 0..9

// uniform_real_distribution: [a, b) half-open
std::uniform_real_distribution<> realDist{0.0, 1.0};  // 0.0 <= x < 1.0

Pitfall 2: Parameters

// Normal: mean, standard deviation
std::normal_distribution<> dist{100.0, 15.0};

// Invalid (negative stddev) — do not do this
// std::normal_distribution<> dist{100.0, -15.0};

auto params = dist.param();
std::cout << "mean: " << params.mean() << std::endl;
std::cout << "stddev: " << params.stddev() << std::endl;

Pitfall 3: Reset

std::mt19937 gen{std::random_device{}()};
std::uniform_int_distribution<> dist{0, 99};

dist.reset();

dist = std::uniform_int_distribution<>{100, 199};

Pitfall 4: Performance

std::mt19937 gen{std::random_device{}()};

// Recreating distribution each iteration
for (int i = 0; i < 1000; ++i) {
    std::uniform_int_distribution<> dist{0, 99};
    int r = dist(gen);
}

// Prefer reuse
std::uniform_int_distribution<> dist{0, 99};
for (int i = 0; i < 1000; ++i) {
    int r = dist(gen);
}

Usage patterns

// 1. Uniform integers
std::uniform_int_distribution<> uniform{0, 99};

// 2. Normal
std::normal_distribution<> normal{0.0, 1.0};

// 3. Weighted choice
std::discrete_distribution<> discrete{weights.begin(), weights.end()};

// 4. Boolean trials
std::bernoulli_distribution bernoulli{0.5};

FAQ

Q1: What is a distribution here?

A: A mapping from a uniform engine output to a chosen probability law (C++11 random).

Q2: Which kinds exist?

A: Uniform, normal, Bernoulli, Poisson, exponential, discrete, and more—see the standard.

Q3: Parameters?

A: They depend on the distribution (mean/stddev for normal, bounds for uniform, etc.).

Q4: Reuse the object?

A: Yes—recreating it in a hot loop is wasteful.

Q5: Integer vs real ranges?

A: Integers are typically inclusive on both ends; reals are often [a, b).

Q6: Learning resources?

A: C++ Primer, Effective Modern C++, cppreference.com.


  • C++ Random | random numbers with <random>
  • C++ random guide | rand() vs modern <random>
  • C++ random_device | hardware entropy for seeding

Practical tips

Tips you can apply in real projects.

Debugging

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

Performance

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

Code review

  • Check common review feedback early.
  • Follow team conventions.

Production checklist

Before coding

  • Is this the right tool for the problem?
  • Can teammates maintain this?
  • Does it meet performance needs?

While coding

  • Are warnings cleared?
  • Edge cases handled?
  • Error handling appropriate?

At review

  • Is intent clear?
  • Tests sufficient?
  • Documented where needed?

Use this checklist to reduce mistakes and improve quality.


C++, distribution, random, probability, C++11


  • C++ Random |
  • C++ random_device |
  • C++ random guide |
  • C++ async & launch |
  • C++ Atomic Operations |