Source
stdlib/random/random.hpp
1
// Copyright (c) 2026 BigBrain LLC. MIT-licensed (see LICENSE).2
// Original work; see ACKNOWLEDGMENTS.md for the open-source ideas we build upon.3
#pragma once5
/**6
* @file random.hpp7
* @brief cheatah `random` — pseudo-random numbers, mirroring the core of8
* Python's `random` module. Backed by a seedable Mersenne Twister9
* (`std::mt19937_64`); `gauss` gives normal deviates for Monte Carlo.10
* `import random` to use it.11
*12
* The engine is PER-THREAD (`thread_local`): concurrent draws from `thread.spawn`ed workers13
* never race, and each thread's stream is independent. A new thread self-seeds from14
* `std::random_device` on first use; `seed(s)` seeds the CALLING thread's engine only, so a15
* worker that wants a reproducible stream calls `seed` itself.16
*17
* Unit tests: `stdlib/tests/random_test.cpp`; the suite runs under18
* AddressSanitizer (the `asan` preset) and Valgrind19
* (`security/run-valgrind.sh`) on every QA-gate run.20
*21
* Doc convention (see also the other stdlib headers): each function documents22
* its runtime complexity with @complexity, its heap allocation with @alloc, and23
* the @test that covers it.24
*/25
#include <cstddef>26
#include <ranges>28
namespace cheatah::random {30
/**31
* Seed the calling thread's engine, making its stream reproducible.32
*33
* Reseeds THIS thread's Mersenne Twister; all `random`/`uniform`/`randint`/`gauss`/`choice`34
* calls on the same thread draw from it, so two runs seeded with the same value produce35
* identical sequences. Until `seed` is called a thread's engine is seeded36
* non-deterministically from `std::random_device` — a `thread.spawn`ed worker that wants37
* reproducibility calls `seed` itself (the main thread's seed does not reach it).38
* @param s the seed.39
* @complexity O(1) time.40
* @alloc none.41
* @concurrency seeds the calling thread's engine only; other threads' streams are unaffected.42
* @test CheatahRandom.SeedMakesTheStreamReproducible43
* @test CheatahRandom.EngineIsPerThread44
* @crtest RandomCompileRun.Seed45
* @systest StdlibE2E.Random46
*/47
void seed(unsigned long long s);48
/**49
* Uniform random double.50
*51
* Draws from the calling thread's engine with a uniform real distribution over52
* the half-open unit interval, so 0.0 can occur but 1.0 cannot.53
* @return a value in [0, 1).54
* @complexity O(1) time.55
* @alloc none.56
* @concurrency thread-safe — draws from the per-thread (`thread_local`) engine, so concurrent draws never race.57
* @test CheatahRandom.RandomInUnitInterval58
* @crtest RandomCompileRun.Random59
* @systest StdlibE2E.Random60
*/61
double random();62
/**63
* Uniform random double in a range.64
*65
* Scales a uniform real distribution to span the given bounds; the caller is66
* expected to pass @p a ≤ @p b (the bounds are not reordered or validated).67
* @param a,b the bounds.68
* @return a value in [@p a, @p b) — the upper bound is excluded, like `random()`.69
* @complexity O(1) time.70
* @alloc none.71
* @concurrency thread-safe — draws from the per-thread (`thread_local`) engine, so concurrent draws never race.72
* @test CheatahRandom.UniformInRange73
* @crtest RandomCompileRun.Uniform74
* @systest StdlibE2E.Random75
*/76
double uniform(double a, double b);77
/**78
* Uniform random integer.79
*80
* Returns each integer in the closed range with equal probability; both @p a and81
* @p b are attainable, and @p a == @p b always yields that value.82
* @param a,b inclusive bounds.83
* @return an integer in [@p a, @p b].84
* @complexity O(1) time.85
* @alloc none.86
* @concurrency thread-safe — draws from the per-thread (`thread_local`) engine, so concurrent draws never race.87
* @test CheatahRandom.RandintInclusiveRange88
* @crtest RandomCompileRun.Randint89
* @systest StdlibE2E.Random90
*/91
long long randint(long long a, long long b);92
/**93
* Normal (Gaussian) deviate.94
*95
* Samples the normal distribution N(@p mu, @p sigma²) from the calling thread's96
* engine; the result is unbounded and can fall on either side of the mean.97
* @param mu mean.98
* @param sigma standard deviation.99
* @return a normal sample.100
* @complexity O(1) time.101
* @alloc none.102
* @concurrency thread-safe — draws from the per-thread (`thread_local`) engine, so concurrent draws never race.103
* @test CheatahRandom.GaussIsFiniteAndReproducible104
* @crtest RandomCompileRun.Gauss105
* @systest StdlibE2E.Random106
*/107
double gauss(double mu, double sigma);109
/**110
* Random element of a random-access sequence (list/array).111
*112
* Picks a uniformly random index in [0, size) via @ref randint and returns a copy113
* of that element.114
* @warning The sequence must be non-empty — an empty @p seq passes an inverted115
* range to @ref randint, which is undefined.116
* @param seq the sequence to pick from (must be non-empty).117
* @return a copy of a uniformly chosen element.118
* @complexity O(1) time.119
* @alloc copies the chosen element — none unless the element's copy itself allocates (e.g. `str`).120
* @concurrency thread-safe — draws its index from the per-thread engine via @ref randint.121
* @test CheatahRandom.Choice122
* @crtest RandomCompileRun.Choice123
* @systest StdlibE2E.Random124
*/125
template <std::ranges::random_access_range R>126
std::ranges::range_value_t<R> choice(const R& seq) {127
const auto n = static_cast<long long>(std::ranges::size(seq));128
return seq[static_cast<std::size_t>(randint(0, n - 1))];129
}131
} // namespace cheatah::random