The C++ random library separates a deterministic engine from a distribution. An engine produces a sequence of uniformly distributed values over its specified output range. A distribution consumes engine output and maps it to a requested statistical distribution. Keep both objects alive when their state must continue.
#include <random>
std::mt19937_64 engine{std::random_device{}()};
std::uniform_int_distribution<int> die{1, 6};
int roll = die(engine); // Both engine and distribution may advance state.
std::mt19937 and std::mt19937_64 are pseudo-random engines: a fixed initial state produces a reproducible sequence. std::default_random_engine is implementation-defined, so it is unsuitable when tests, files, or protocols require the same sequence across implementations.
Seed According to the Requirement #
A deterministic test should use an explicit documented seed. Record the seed on a test failure when generated data must be reproduced.
std::mt19937 engine{0x5EEDu};std::random_device is intended to provide non-deterministic random numbers when the implementation has a suitable source, but an implementation may provide a deterministic fallback. Its entropy() value is an estimate and may be zero when no estimate is available. Therefore, random_device is appropriate as a best-effort seed source for non-cryptographic simulations, not as a portable cryptographic-security guarantee. Use the operating system’s cryptographic random API or a vetted cryptographic library for keys, tokens, salts, and nonces.
A std::seed_seq can expand several source words into engine state. Avoid seeding several long-lived engines with the same small integer when independent streams are required; establish and document a stream-allocation policy instead.
Distributions Produce Bounded Values without Modulo Bias #
Use the distribution that expresses the desired result:
std::uniform_int_distribution<int> index{0, static_cast<int>(size - 1)};
std::bernoulli_distribution enabled{0.25};
std::normal_distribution<double> noise{0.0, 1.0};uniform_int_distribution has inclusive bounds. Validate a dynamic bound before constructing or parameterizing it: a range with a > b violates the distribution’s precondition. Do not use engine() % n for a bounded uniform result unless the engine’s output range divides n; otherwise some residues occur more often. A standard distribution performs the required rejection or mapping work for its specified distribution.
Distributions are not interchangeable with engines. A distribution can retain state—for example, an implementation of a normal distribution may cache a generated value—so preserve or reset distribution state according to the simulation’s reproducibility requirement.
Lifetime, Reproducibility, and Serialization #
Passing an engine by value intentionally creates a separate sequence state. Pass it by reference when a helper must advance the caller’s sequence.
int roll_die(std::mt19937_64& engine) {
static std::uniform_int_distribution<int> die{1, 6};
return die(engine);
}The static distribution is safe here only when calls are synchronized; it may have mutable state. Better, make distribution ownership explicit when its parameters or state differ per simulation.
Standard engines support formatted stream input and output for state, which supports checkpoints within the same standard engine specification. Persist the engine type, seed policy, and distribution parameters beside serialized state. A serialized sequence is not a cryptographic secret store, and a project should not claim cross-version reproducibility beyond the guarantees of the selected engine and implementation environment.
Concurrency #
Engine and distribution objects are mutable state and must not be concurrently modified without synchronization. Give each thread its own engine and distribution when streams are independent, or protect a shared generator with a mutex when one ordered sequence is required. Thread-local generators need a deliberate seed policy; naively copying the same seed into every thread creates correlated identical streams rather than parallel randomness.
Comments
Read or comment on GitHub (sign-in required to comment)