C++ PROGRAMMING ยท 10 MIN STUDY

Random numbers with the C++ random library

Generate reproducible random values using engines, seeds, and probability distributions.

Learning objectives

  • Distinguish a pseudo-random engine from a probability distribution.
  • Seed an engine once and explain when fixed seeds are useful.
  • Generate values with uniform integer, uniform real, and normal distributions.
  • Recognize why general-purpose engines are not suitable for security-sensitive tokens.

Prerequisites: understand loops, functions, and standard-library headers. Review Loops and Functions first. Examples use C++11 or later.

Why use the random library?

Random-number generation is used in simulations, games, sampling, and randomized algorithms. C++ separates a random engine (which produces a sequence of pseudo-random bits) from a distribution (which maps those bits to values with a chosen probability pattern).

Generate an integer in a range

#include <iostream>
#include <random>
int main() {
    std::mt19937 engine(2026); // fixed seed: repeatable sequence
    std::uniform_int_distribution<int> die(1, 6);
    for (int i = 0; i < 5; ++i) std::cout << die(engine) << ' ';
}

mt19937 is a widely used pseudo-random engine. A fixed seed makes the engine sequence repeatable, which is valuable for tests and debugging. The standard specifies the mt19937 engine sequence, but it does not require every standard-library implementation to produce identical sampled values for each distribution. Therefore, the same seed can give different distribution outputs across library implementations. The engine and its distributions are not cryptographically secure.

Seed choices

#include <random>
std::random_device source;
std::mt19937 engine(source());

This asks random_device for seed material. The implementation may use a nondeterministic source or may fall back to a deterministic mechanism; do not assume it guarantees cryptographic entropy on every platform.

Different distributions

#include <random>
std::uniform_real_distribution<double> probability(0.0, 1.0);
std::normal_distribution<double> measurements(10.0, 2.0);
double p = probability(engine);
double sample = measurements(engine);

Uniform integer distributions include both endpoints. Uniform real distributions use a half-open interval in the standard specification. A normal distribution is characterized by a mean and standard deviation; its values are not restricted to a fixed range.

Common mistakes

  • Calling rand() repeatedly without understanding seeding and distribution quality.
  • Reseeding the engine for every generated value.
  • Using a fixed seed when fresh sequences are actually required, or a changing seed when reproducibility is required.
  • Using a general-purpose engine for passwords, tokens, or security keys.

Practice

  1. Why are engine and distribution separate?
  2. Why is a fixed seed useful in a unit test?
  3. Is mt19937 suitable for generating password-reset tokens?
Show answers
  1. The engine supplies pseudo-random bits; the distribution shapes them into a desired statistical range.
  2. It makes the generated sequence repeatable.
  3. No. Use a cryptographically secure source provided by the platform or security library.

Summary

Choose an engine, seed it once for the intended reproducibility, and use a distribution that matches the problem. Never treat ordinary pseudo-random engines as cryptographic generators.

References