Ch12.2: Distributions
Overview
Random number engines produce raw random bits, but most applications need random values in
specific ranges or following specific statistical distributions. C++'s
<random> library provides distributions that transform
raw random bits into the desired output format.
Common distributions include:
::std::uniform_int_distribution— uniform integers in a range::std::uniform_real_distribution— uniform floating-point values::std::bernoulli_distribution— boolean values with given probability::std::normal_distribution— normal (Gaussian) distribution
uniform_int_distribution
Generates uniformly distributed integers in a specified range [min, max].
#include <fast_io.h>
#include <random>
int main() {
using namespace ::fast_io::io;
::std::mt19937_64 eng{12345u}; // Seeded for reproducibility
// Generate integers in [1, 6] (like a die roll)
::std::uniform_int_distribution<int> die_dist(1, 6);
println("Rolling a die 10 times:");
for (::std::size_t i{}; i != 10; ++i) {
print(die_dist(eng), " ");
}
print("\n");
// Generate integers in [0, 99]
::std::uniform_int_distribution<int> percent_dist(0, 99);
println("Random percentages:");
for (::std::size_t i{}; i != 10; ++i) {
print(percent_dist(eng), "% ");
}
print("\n");
}
Never use modulo to generate ranges! Using
eng() % 100 to get
values in [0, 99] creates biased distributions due to the pigeonhole principle. Always use
::std::uniform_int_distribution which uses rejection sampling to ensure perfect
uniformity.
bernoulli_distribution
Generates boolean values (true or false) with a specified
probability p of being true.
#include <fast_io.h>
#include <random>
int main() {
using namespace ::fast_io::io;
::std::mt19937_64 eng{12345u};
// Fair coin: 50% heads
::std::bernoulli_distribution fair_coin(0.5);
println("Flipping a fair coin 10 times:");
for (::std::size_t i{}; i != 10; ++i) {
print(fair_coin(eng) ? "H" : "T", " ");
}
print("\n");
// Biased coin: 70% heads
::std::bernoulli_distribution biased_coin(0.7);
println("Flipping a biased coin (70% heads):");
for (::std::size_t i{}; i != 10; ++i) {
print(biased_coin(eng) ? "H" : "T", " ");
}
print("\n");
// Rare event: 5% chance
::std::bernoulli_distribution rare_event(0.05);
println("Simulating rare events (5% chance):");
::std::size_t count{};
for (::std::size_t i{}; i != 100; ++i) {
if (rare_event(eng)) {
++count;
}
}
println("Occurred ", count, " times out of 100");
}
Combining Distributions
You can use multiple distributions together for complex scenarios:
#include <fast_io.h>
#include <random>
int main() {
using namespace ::fast_io::io;
::std::mt19937_64 eng{12345u};
// Distribution for number of items (1-5)
::std::uniform_int_distribution<int> count_dist(1, 5);
// Distribution for item values (10-99)
::std::uniform_int_distribution<int> value_dist(10, 99);
// Generate random number of random values
int num_items = count_dist(eng);
println("Generating ", num_items, " items:");
for (int i{}; i != num_items; ++i) {
println(" Item ", i + 1, ": ", value_dist(eng));
}
}
Distribution Properties
All distributions provide these methods:
| Method | Description |
|---|---|
operator()(gen) |
Generates the next random value using the engine |
min() |
Returns the minimum value the distribution can produce |
max() |
Returns the maximum value the distribution can produce |
reset() |
Resets the distribution's internal state |
param() |
Gets or sets the distribution parameters |
Key Takeaways
- Distributions transform raw random bits from engines into values with specific statistical properties.
-
Use
::std::uniform_int_distributionfor integers in a range — never use modulo. -
Use
::std::bernoulli_distributionfor boolean values with a given probability. -
Distributions work with any engine, including
::std::mt19937_64and::fast_io::ibuf_white_hole_engine. -
For cryptographically secure randomness, use
ibuf_white_hole_engineinstead ofmt19937_64.