From ce29b3e559d0780a83a436d1aee82cc28279f94f Mon Sep 17 00:00:00 2001 From: Menace Date: Sat, 21 Feb 2026 22:33:20 +0100 Subject: [PATCH 1/6] C++ PRNG article --- bot-articles/random.md | 46 ------- wiki/cpp-tutorial/random.md | 228 +++++++++++++++++++++++++++++++++++ wiki/cpp-tutorial/sidebar.ts | 5 + 3 files changed, 233 insertions(+), 46 deletions(-) delete mode 100644 bot-articles/random.md create mode 100644 wiki/cpp-tutorial/random.md diff --git a/bot-articles/random.md b/bot-articles/random.md deleted file mode 100644 index 12825be..0000000 --- a/bot-articles/random.md +++ /dev/null @@ -1,46 +0,0 @@ -# Generating Random Numbers in C++ - -The [][1] header in C++ provides (pseudo-)random number generation (PRNG): -- *[UniformRandomBitGenerators][2]* produce random bits (entropy) -- *[RandomNumberDistributions][3]* use entropy to generate random numbers - -[1]: https://en.cppreference.com/w/cpp/header/random -[2]: https://en.cppreference.com/w/cpp/named_req/UniformRandomBitGenerators -[3]: https://en.cppreference.com/w/cpp/named_req/RandomNumberDistribution - -## Example: Printing Ten Random Dice Rolls -```cpp -#include -#include -int main() { - std::random_device dev; // for seeding - std::default_random_engine gen{dev()}; - std::uniform_int_distribution dis{1, 6}; - for (int i = 0; i < 10; ++i) - std::cout << dis(gen) << ' '; -} -``` - -## Possible Output (will be different each time) -```cpp -1 1 6 5 2 2 5 5 6 2 -``` - - -## Common Generators -- **[std::random_device](https://en.cppreference.com/w/cpp/numeric/random/random_device)**: truly random -- **[std::default_random_engine](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:default_random_engine)** -- **[std::mt19937](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:mt19937)**: popular default choice - - -## Common Distributions -- **[std::uniform_int_distribution](https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution)** -- **[std::uniform_real_distribution](https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution)** -- **[std::normal_distribution](https://en.cppreference.com/w/cpp/numeric/random/normal_distribution)** - -## See Also -- [Pseudo-random number generation](https://en.cppreference.com/w/cpp/numeric/random)
-<:stackoverflow:1074747016644661258> -[Generate random numbers using C++11 random library](https://stackoverflow.com/q/19665818/5740428)
-<:stackoverflow:1074747016644661258> -[Why is the use of rand() considered bad?](https://stackoverflow.com/q/52869166/5740428) diff --git a/wiki/cpp-tutorial/random.md b/wiki/cpp-tutorial/random.md new file mode 100644 index 0000000..bd3f3d4 --- /dev/null +++ b/wiki/cpp-tutorial/random.md @@ -0,0 +1,228 @@ +--- +bot_article: | + # Generating Random Numbers in C++ + ## Example: Printing Ten Random Dice Rolls + + ```cpp + #include + #include + int main() { + std::random_device dev; // for seeding + std::default_random_engine gen{dev()}; + std::uniform_int_distribution dis{1, 6}; + for (int i = 0; i < 10; ++i) { + std::cout << dis(gen) << ' '; + } + } + ``` + + ## Possible Output (will be different each time) + ```cpp + 1 1 6 5 2 2 5 5 6 2 + ``` +--- + +# Generating Random Numbers + +A [Pseudorandom Number Generator (PRNG)](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) is an algorithm +for generating a deterministic sequence of numbers that appear random. PRNGs maintain an internal state that is updated +each time a new number is generated. The initial state of the PRNG is called the seed and the process of setting the +initial state is called seeding. Two instances of the same PRNG initialized with the same seed will produce identical +sequences of numbers, which is important for reproducibility of statistical simulations. + +In the [C++ standard library](https://en.cppreference.com/w/cpp/header/random), random engines are callable objects that +implement PRNG algorithms behind a +[shared interface](https://en.cppreference.com/w/cpp/named_req/RandomNumberEngine.html). A common example is +`std::default_random_engine`, which serves as a standard, general-purpose generator. + +It should be noted that none of these PRNGs are cryptographically secure (should not be used for security-sensitive +applications). This means that the state of the random engine can be figured out and predicted given enough values. + +### Example: Printing Ten Random Dice Rolls + +```cpp +#include +#include + +int main() { + // initialize a random device + std::random_device dev; + + // seed default_random_engine + std::default_random_engine gen{dev()}; + + // initialize a uniform integer distribution + std::uniform_int_distribution dis{1, 6}; + + // roll the dice + for (int i = 0; i < 10; ++i) { + std::cout << dis(gen) << ' '; + } +} +``` + +## Seeding PRNGs + +### Random Device + +A random device ([std::random_device](https://en.cppreference.com/w/cpp/numeric/random/random_device)) is random number +generator that attempts to utilize randomness from a non-deterministic source, typically provided by the operating +system (e.g. reading from `/dev/random` or `/dev/urandom` on UNIX-like systems). If no source of randomness is available +then it might fall back to using a deterministic [random engine](https://eel.is/c++draft/rand.device#2). This means that +two instances of `std::random_device` can produce the same sequence of numbers. However it is rarely the case on the +three major platforms (Windows, Linux, and macOS) in modern environments. + +The random device should primarily be used for seeding random engines as it is slow and usually requires system calls. +On some UNIX-like systems, if `/dev/random` is used as the source of random numbers, it may block when the entropy pool +is exhausted (though this is generally no longer the case on modern systems). Additionally, the behavior of +`std::random_device` is implementation-defined. + +### Example: Creating a random device out of `/dev/urandom` on UNIX-like systems + +Using `/dev/random` might be preferred in the +[majority of cases](https://unix.stackexchange.com/questions/324209/when-to-use-dev-random-vs-dev-urandom). It is +however unclear if there is any actual difference between `/dev/random` and `/dev/urandom` as is implementation defined +and can vary system to system. + +```cpp +#include +#include + +int main() { + // initialize a random device + std::random_device dev{"/dev/urandom"}; + + // generate seeds directly + for (int i = 0; i < 10; ++i) { + auto seed = dev(); + std::cout << seed << '\n'; + } +} +``` + +### Seed Sequence + +Seed sequence (`std::seed_seq`) is a utility in the standard library for converting a small number of inputs into a +higher quality seed (does not contain large areas of zeros/ones) suitable for seeding PRNGs with large internal state +(e.g. `std::mt19937`). + +## Predefined Generators + +| Name | Generator | +| --------------------- | ------------------------- | +| default_random_engine | implementation defined | +| minstd_rand0 | linear congruential | +| minstd_rand | linear congruential | +| mt19937 | mersenne twister | +| mt19937_64 | mersenne twister | +| ranlux24 | subtract with carry | +| ranlux48 | subtract with carry | +| knuth_b | minstd_rand0 with shuffle | +| philox4x32 (C++26) | counter-based philox | +| philox4x64 (C++26) | counter-based philox | + +[source](https://timsong-cpp.github.io/cppwp/n4868/rand.predef) + +### Linear Congruential Generator + +[Linear congruential generator (LCG)](https://en.wikipedia.org/wiki/Linear_congruential_generator) is a very simple +pseudo PRNG with a small internal state (`sizeof(std::int_fast32_t)` bytes). The C++ standard library provides three +predefined LCG-based engines [`minstd_rand0`](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:minstd_rand0), +[`minstd_rand`](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:minstd_rand) and +[`knuth_b`](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:knuth_b). The statistical quality of these +generators is not considered good by modern standards. + +```cpp +#include +#include +#include + +int main() { + // Musl rand() reconstruction + using musl_rand = std::linear_congruential_engine< + std::uint64_t, + 6364136223846793005, + 1, + 0 // 2^64 + >; + + // initialize generator with seed + musl_rand gen(123456789); + + // generate random numbers + for (int i = 0; i < 10; ++i) { + auto random_number = gen(); + std::cout << random_number << std::endl; + } +} +``` + +### Mersenne Twister + +[Mersenne Twister (MT)](https://en.wikipedia.org/wiki/Mersenne_Twister) is a general-purpose PRNG with decent +statistical properties. The C++ standard library provides three predefined MT-based engines +[`mt19937`](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:mt19937) and +[`mt19937_64`](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:mt19937_64). The main limitations of the +Mersenne Twister engine are large internal state (624 \* `sizeof(std::uint_fast32_t)` bytes) and difficulty of it's +seeding. + +```cpp +#include +#include + +int main() { + // initialize seed sequence + std::seed_seq seq{1, 2, 3, 4}; + + // initialize Mersenne Twister engine with seed sequence + std::mt19937 gen(seq); + + // initialize a uniform real distribution + std::uniform_real_distribution dis{0.0, 1.0}; + + // generate random numbers in the interval [0, 1) + for (int i = 0; i < 100; ++i) { + double random_number = dis(gen); + std::cout << random_number << std::endl; + } +} +``` + +### Ranlux (Subtract With Carry) + +[Ranlux](https://luscher.web.cern.ch/luscher/ranlux/) is a PRNG with a high statistical quality. The C++ standard +library provides two predefined ranlux-based engines `ranlux24` and `ranlux48`. The ranlux PRNGs are widely used in +[Monte Carlo simulation](https://en.wikipedia.org/wiki/Monte_Carlo_method) programs. + +### Philox + +Two philox random engines (philox4x32 and philox4x64) just got added into the +[C++26 standard](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2075r1.pdf). As of the time of writing this +article neither of them are implemented in both libstdc++ and libc++. + +### Adapters + +The standard library also provides engine adapters, which improve the statistical qualities of random engines. + +- **[std::discard_block_engine](https://en.cppreference.com/w/cpp/numeric/random/discard_block_engine.html)** +- **[std::independent_bits_engine](https://en.cppreference.com/w/cpp/numeric/random/independent_bits_engine.html)** +- **[std::shuffle_order_engine](https://en.cppreference.com/w/cpp/numeric/random/shuffle_order_engine.html)** + +### Distributions + +- **[std::uniform_int_distribution](https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution)** +- **[std::uniform_real_distribution](https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution)** +- **[std::normal_distribution](https://en.cppreference.com/w/cpp/numeric/random/normal_distribution)** +- **[all distributions](https://en.cppreference.com/w/cpp/named_req/RandomNumberDistribution)** + +### See Also + +- **[UniformRandomBitGenerators](https://en.cppreference.com/w/cpp/named_req/UniformRandomBitGenerator)** +- **[Pseudo-random number generation](https://en.cppreference.com/w/cpp/numeric/random)** +- **[Generate random numbers using C++11 random library](https://stackoverflow.com/q/19665818/5740428)** +- **[Why is the use of rand() considered bad?](https://stackoverflow.com/q/52869166/5740428)** +- **[ChaCha20](https://cr.yp.to/chacha.html)** +- **[A PRNG Shootout](https://prng.di.unimi.it/)** +- **[PCG Random](https://pcg-random.org/)** +- **[myths about urandom](https://www.2uo.de/myths-about-urandom/)** +- **[boost::random](https://www.boost.org/library/latest/random/)** diff --git a/wiki/cpp-tutorial/sidebar.ts b/wiki/cpp-tutorial/sidebar.ts index 019b2e4..7e53937 100644 --- a/wiki/cpp-tutorial/sidebar.ts +++ b/wiki/cpp-tutorial/sidebar.ts @@ -171,6 +171,11 @@ const sidebar = [ ], collapsed: true, }, + { + text: "Random", + link: "/cpp-tutorial/random", + collapsed: true, + }, ], }, ]; From 1fe1e92cf5f7bc0056ebedfd179634c32c68d0fe Mon Sep 17 00:00:00 2001 From: Menace <155697298+ProfessionalMenace@users.noreply.github.com> Date: Fri, 27 Feb 2026 20:57:40 +0100 Subject: [PATCH 2/6] Typos Co-authored-by: Jeremy Rifkin <51220084+jeremy-rifkin@users.noreply.github.com> --- wiki/cpp-tutorial/random.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wiki/cpp-tutorial/random.md b/wiki/cpp-tutorial/random.md index bd3f3d4..95757c7 100644 --- a/wiki/cpp-tutorial/random.md +++ b/wiki/cpp-tutorial/random.md @@ -160,10 +160,10 @@ int main() { ### Mersenne Twister [Mersenne Twister (MT)](https://en.wikipedia.org/wiki/Mersenne_Twister) is a general-purpose PRNG with decent -statistical properties. The C++ standard library provides three predefined MT-based engines +statistical properties. The C++ standard library provides two predefined MT-based engines [`mt19937`](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:mt19937) and [`mt19937_64`](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:mt19937_64). The main limitations of the -Mersenne Twister engine are large internal state (624 \* `sizeof(std::uint_fast32_t)` bytes) and difficulty of it's +Mersenne Twister engine are large internal state (624 \* `sizeof(std::uint_fast32_t)` bytes) and difficulty of its seeding. ```cpp From 0c3a8f1e06dd896ec708679d94700333e68b800c Mon Sep 17 00:00:00 2001 From: Menace Date: Wed, 4 Mar 2026 11:32:09 +0100 Subject: [PATCH 3/6] beginnerification --- wiki/cpp-tutorial/random.md | 200 +++++++++++++++++------------------- 1 file changed, 92 insertions(+), 108 deletions(-) diff --git a/wiki/cpp-tutorial/random.md b/wiki/cpp-tutorial/random.md index 95757c7..aa59e6a 100644 --- a/wiki/cpp-tutorial/random.md +++ b/wiki/cpp-tutorial/random.md @@ -6,12 +6,20 @@ bot_article: | ```cpp #include #include + int main() { - std::random_device dev; // for seeding + // initialize a random device + std::random_device dev; + + // seed default_random_engine std::default_random_engine gen{dev()}; + + // initialize a uniform integer distribution std::uniform_int_distribution dis{1, 6}; + + // roll the dice for (int i = 0; i < 10; ++i) { - std::cout << dis(gen) << ' '; + std::cout << dis(gen) << ' '; } } ``` @@ -25,20 +33,35 @@ bot_article: | # Generating Random Numbers A [Pseudorandom Number Generator (PRNG)](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) is an algorithm -for generating a deterministic sequence of numbers that appear random. PRNGs maintain an internal state that is updated -each time a new number is generated. The initial state of the PRNG is called the seed and the process of setting the -initial state is called seeding. Two instances of the same PRNG initialized with the same seed will produce identical -sequences of numbers, which is important for reproducibility of statistical simulations. +for generating a sequence of (almost) random numbers. PRNGs maintain an internal state that is updated each time a new +number is generated. The initial state of the PRNG is called the seed and the process of setting the initial state is +called seeding. In the [C++ standard library](https://en.cppreference.com/w/cpp/header/random), random engines are callable objects that implement PRNG algorithms behind a -[shared interface](https://en.cppreference.com/w/cpp/named_req/RandomNumberEngine.html). A common example is -`std::default_random_engine`, which serves as a standard, general-purpose generator. +[shared interface](https://en.cppreference.com/w/cpp/named_req/RandomNumberEngine.html). + +Unlike the C `rand()` function, which relies on common shared seed via `srand()`, the C++ random engines are independent +and each one has its own seed. This ensures thread safety, whereas C `rand()` does not. Another thing worth mentioning +about `rand()` is that it is implementation defined and can vary system to system. The C++ random library should be +always preferred. It should be noted that none of these PRNGs are cryptographically secure (should not be used for security-sensitive applications). This means that the state of the random engine can be figured out and predicted given enough values. -### Example: Printing Ten Random Dice Rolls +A common example of a random engine is `std::default_random_engine`, which serves as a standard, general-purpose +generator. + +## Example: Printing Ten Random Dice Rolls + +First, include the `` header containing the random library. Then create a random number engine and seed it. The +seed determines the sequence of numbers produced. + +If you were to use a fixed seed (e.g. `std::default_random_engine gen{42};`) then the program will generate the same +sequence every time it runs. To generate a unique sequence of numbers each time, obtain a random seed from a random +device. + +To ensure fairness of dice rolls redistribute the output of random engine using a uniform int distribution. ```cpp #include @@ -61,110 +84,58 @@ int main() { } ``` -## Seeding PRNGs - -### Random Device +## Random Device A random device ([std::random_device](https://en.cppreference.com/w/cpp/numeric/random/random_device)) is random number generator that attempts to utilize randomness from a non-deterministic source, typically provided by the operating -system (e.g. reading from `/dev/random` or `/dev/urandom` on UNIX-like systems). If no source of randomness is available -then it might fall back to using a deterministic [random engine](https://eel.is/c++draft/rand.device#2). This means that -two instances of `std::random_device` can produce the same sequence of numbers. However it is rarely the case on the -three major platforms (Windows, Linux, and macOS) in modern environments. +system (e.g. reading from `/dev/random` or `/dev/urandom` on UNIX-like systems). The random device should primarily be used for seeding random engines as it is slow and usually requires system calls. -On some UNIX-like systems, if `/dev/random` is used as the source of random numbers, it may block when the entropy pool -is exhausted (though this is generally no longer the case on modern systems). Additionally, the behavior of -`std::random_device` is implementation-defined. -### Example: Creating a random device out of `/dev/urandom` on UNIX-like systems +## Mersenne Twister -Using `/dev/random` might be preferred in the -[majority of cases](https://unix.stackexchange.com/questions/324209/when-to-use-dev-random-vs-dev-urandom). It is -however unclear if there is any actual difference between `/dev/random` and `/dev/urandom` as is implementation defined -and can vary system to system. +[Mersenne Twister (MT)](https://en.wikipedia.org/wiki/Mersenne_Twister) is a general-purpose PRNG with good statistical +properties and a very fast speed. -```cpp -#include -#include +The C++ standard library provides two predefined MT-based engines the 32 bit version +[`mt19937`](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:mt19937) and the 64 bit version +[`mt19937_64`](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:mt19937_64). -int main() { - // initialize a random device - std::random_device dev{"/dev/urandom"}; +The name `mt19937` comes from the fact that Mersenne Twister algorithm is based on Mersenne primes—specifically the +prime number $2^{19937} - 1$. It is also the number of possible states MT will reach before returning back to the +initial state. - // generate seeds directly - for (int i = 0; i < 10; ++i) { - auto seed = dev(); - std::cout << seed << '\n'; - } -} -``` - -### Seed Sequence - -Seed sequence (`std::seed_seq`) is a utility in the standard library for converting a small number of inputs into a -higher quality seed (does not contain large areas of zeros/ones) suitable for seeding PRNGs with large internal state -(e.g. `std::mt19937`). - -## Predefined Generators - -| Name | Generator | -| --------------------- | ------------------------- | -| default_random_engine | implementation defined | -| minstd_rand0 | linear congruential | -| minstd_rand | linear congruential | -| mt19937 | mersenne twister | -| mt19937_64 | mersenne twister | -| ranlux24 | subtract with carry | -| ranlux48 | subtract with carry | -| knuth_b | minstd_rand0 with shuffle | -| philox4x32 (C++26) | counter-based philox | -| philox4x64 (C++26) | counter-based philox | - -[source](https://timsong-cpp.github.io/cppwp/n4868/rand.predef) - -### Linear Congruential Generator - -[Linear congruential generator (LCG)](https://en.wikipedia.org/wiki/Linear_congruential_generator) is a very simple -pseudo PRNG with a small internal state (`sizeof(std::int_fast32_t)` bytes). The C++ standard library provides three -predefined LCG-based engines [`minstd_rand0`](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:minstd_rand0), -[`minstd_rand`](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:minstd_rand) and -[`knuth_b`](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:knuth_b). The statistical quality of these -generators is not considered good by modern standards. +The main limitation of the MT engine is its large internal state size of exactly `624 * sizeof(std::uint_fast32_t)` +bytes for `mt19937`. Because of this size MT engine makes is less suitable for multi-threaded applications than other +PRNGs with a smaller state. ```cpp #include #include -#include int main() { - // Musl rand() reconstruction - using musl_rand = std::linear_congruential_engine< - std::uint64_t, - 6364136223846793005, - 1, - 0 // 2^64 - >; - - // initialize generator with seed - musl_rand gen(123456789); - - // generate random numbers - for (int i = 0; i < 10; ++i) { - auto random_number = gen(); - std::cout << random_number << std::endl; + // initialize a random device + std::random_device dev; + + // initialize Mersenne Twister engine with seed sequence + std::mt19937 gen{dev()}; + + // initialize a uniform real distribution + std::uniform_real_distribution dis{0.0, 1.0}; + + // generate random numbers in the interval [0, 1) + for (int i = 0; i < 100; ++i) { + double random_number = dis(gen); + std::cout << random_number << std::endl; } } ``` -### Mersenne Twister +## Seed Sequence -[Mersenne Twister (MT)](https://en.wikipedia.org/wiki/Mersenne_Twister) is a general-purpose PRNG with decent -statistical properties. The C++ standard library provides two predefined MT-based engines -[`mt19937`](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:mt19937) and -[`mt19937_64`](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:mt19937_64). The main limitations of the -Mersenne Twister engine are large internal state (624 \* `sizeof(std::uint_fast32_t)` bytes) and difficulty of its -seeding. +Seed sequence (`std::seed_seq`) is an utility in the standard library for converting a small number of inputs into a +higher quality seed (does not contain large areas of zeros/ones) suitable for seeding PRNGs with large internal state +(e.g. `std::mt19937`). ```cpp #include @@ -175,7 +146,7 @@ int main() { std::seed_seq seq{1, 2, 3, 4}; // initialize Mersenne Twister engine with seed sequence - std::mt19937 gen(seq); + std::mt19937 gen{seq}; // initialize a uniform real distribution std::uniform_real_distribution dis{0.0, 1.0}; @@ -188,34 +159,47 @@ int main() { } ``` -### Ranlux (Subtract With Carry) +## Linear Congruential Generator -[Ranlux](https://luscher.web.cern.ch/luscher/ranlux/) is a PRNG with a high statistical quality. The C++ standard -library provides two predefined ranlux-based engines `ranlux24` and `ranlux48`. The ranlux PRNGs are widely used in -[Monte Carlo simulation](https://en.wikipedia.org/wiki/Monte_Carlo_method) programs. +[Linear congruential generator (LCG)](https://en.wikipedia.org/wiki/Linear_congruential_generator) is a very simple PRNG +with a small internal state of `sizeof(std::int_fast32_t)` bytes. -### Philox +The C++ standard library provides three predefined LCG-based engines +[`minstd_rand0`](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:minstd_rand0) (minimal standard 0), +[`minstd_rand`](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:minstd_rand) (minimal standard) and +[`knuth_b`](https://timsong-cpp.github.io/cppwp/n4868/rand.predef#lib:knuth_b) (shuffled LCG). -Two philox random engines (philox4x32 and philox4x64) just got added into the -[C++26 standard](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2075r1.pdf). As of the time of writing this -article neither of them are implemented in both libstdc++ and libc++. +The statistical quality of all these 3 generators is not considered good by modern standards. Typically LCG are +considered fast but `minstd_rand0` and `minstd_rand` are not necessarily faster than `mt19937` on modern hardware. The +`knuth_b` engine slightly improves the statistical properties of `minstd_rand0` by shuffling the generated sequence. -### Adapters +## Predefined Generators -The standard library also provides engine adapters, which improve the statistical qualities of random engines. +| Name | Generator | Summary | +| --------------------- | ------------------------- | -------------------------------------- | +| default_random_engine | implementation defined | Reproducibility is not important | +| minstd_rand0 | linear congruential | Small internal state | +| minstd_rand | linear congruential | Small internal state | +| mt19937 | mersenne twister | Generally should be preferred | +| mt19937_64 | mersenne twister | Generally should be preferred | +| ranlux24 | subtract with carry | Statistical quality | +| ranlux48 | subtract with carry | Statistical quality | +| knuth_b | minstd_rand0 with shuffle | Almost no reason to use it | +| philox4x32 (C++26) | counter-based philox | Good for multi-threaded applications\* | +| philox4x64 (C++26) | counter-based philox | Good for multi-threaded applications\* | + +\*Not yet implemented -- **[std::discard_block_engine](https://en.cppreference.com/w/cpp/numeric/random/discard_block_engine.html)** -- **[std::independent_bits_engine](https://en.cppreference.com/w/cpp/numeric/random/independent_bits_engine.html)** -- **[std::shuffle_order_engine](https://en.cppreference.com/w/cpp/numeric/random/shuffle_order_engine.html)** +[source](https://timsong-cpp.github.io/cppwp/n4868/rand.predef) -### Distributions +## Distributions - **[std::uniform_int_distribution](https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution)** - **[std::uniform_real_distribution](https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution)** - **[std::normal_distribution](https://en.cppreference.com/w/cpp/numeric/random/normal_distribution)** - **[all distributions](https://en.cppreference.com/w/cpp/named_req/RandomNumberDistribution)** -### See Also +## See Also - **[UniformRandomBitGenerators](https://en.cppreference.com/w/cpp/named_req/UniformRandomBitGenerator)** - **[Pseudo-random number generation](https://en.cppreference.com/w/cpp/numeric/random)** From 9ef1958f290e6ba3766defbd0e5faf2a1615191a Mon Sep 17 00:00:00 2001 From: Menace <155697298+ProfessionalMenace@users.noreply.github.com> Date: Tue, 16 Jun 2026 04:18:36 +0200 Subject: [PATCH 4/6] Apply suggestions from code review Co-authored-by: Jeremy Rifkin <51220084+jeremy-rifkin@users.noreply.github.com> --- wiki/cpp-tutorial/random.md | 29 ++++++++++------------------- wiki/cpp-tutorial/sidebar.ts | 1 - 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/wiki/cpp-tutorial/random.md b/wiki/cpp-tutorial/random.md index aa59e6a..6fb5223 100644 --- a/wiki/cpp-tutorial/random.md +++ b/wiki/cpp-tutorial/random.md @@ -1,25 +1,17 @@ --- bot_article: | # Generating Random Numbers in C++ - ## Example: Printing Ten Random Dice Rolls +Simple example of random number generation in C++: ```cpp #include #include - int main() { - // initialize a random device - std::random_device dev; - - // seed default_random_engine - std::default_random_engine gen{dev()}; - - // initialize a uniform integer distribution - std::uniform_int_distribution dis{1, 6}; - - // roll the dice + std::random_device dev; // for seeding + std::default_random_engine rng{dev()}; + std::uniform_int_distribution dist{1, 6}; for (int i = 0; i < 10; ++i) { - std::cout << dis(gen) << ' '; + std::cout << dist(rng) << ' '; } } ``` @@ -43,8 +35,8 @@ implement PRNG algorithms behind a Unlike the C `rand()` function, which relies on common shared seed via `srand()`, the C++ random engines are independent and each one has its own seed. This ensures thread safety, whereas C `rand()` does not. Another thing worth mentioning -about `rand()` is that it is implementation defined and can vary system to system. The C++ random library should be -always preferred. +about `rand()` is that it is implementation defined and can vary system to system. The C++ random library should +always be preferred. It should be noted that none of these PRNGs are cryptographically secure (should not be used for security-sensitive applications). This means that the state of the random engine can be figured out and predicted given enough values. @@ -106,7 +98,7 @@ prime number $2^{19937} - 1$. It is also the number of possible states MT will r initial state. The main limitation of the MT engine is its large internal state size of exactly `624 * sizeof(std::uint_fast32_t)` -bytes for `mt19937`. Because of this size MT engine makes is less suitable for multi-threaded applications than other +bytes for `mt19937`. Because of this size MT engine makes it less suitable for multi-threaded applications than other PRNGs with a smaller state. ```cpp @@ -125,15 +117,14 @@ int main() { // generate random numbers in the interval [0, 1) for (int i = 0; i < 100; ++i) { - double random_number = dis(gen); - std::cout << random_number << std::endl; + std::cout << dis(gen) << std::endl; } } ``` ## Seed Sequence -Seed sequence (`std::seed_seq`) is an utility in the standard library for converting a small number of inputs into a +Seed sequence (`std::seed_seq`) is a utility in the standard library for converting a small number of inputs into a higher quality seed (does not contain large areas of zeros/ones) suitable for seeding PRNGs with large internal state (e.g. `std::mt19937`). diff --git a/wiki/cpp-tutorial/sidebar.ts b/wiki/cpp-tutorial/sidebar.ts index 7e53937..0003f93 100644 --- a/wiki/cpp-tutorial/sidebar.ts +++ b/wiki/cpp-tutorial/sidebar.ts @@ -174,7 +174,6 @@ const sidebar = [ { text: "Random", link: "/cpp-tutorial/random", - collapsed: true, }, ], }, From 8c0d0d5519cbd725907d63fa4e25264c9ca2e7ef Mon Sep 17 00:00:00 2001 From: ProfessionalMenace Date: Thu, 2 Jul 2026 23:52:45 +0200 Subject: [PATCH 5/6] applied suggestions --- wiki/cpp-tutorial/random.md | 76 +++++++++++++------------------------ 1 file changed, 26 insertions(+), 50 deletions(-) diff --git a/wiki/cpp-tutorial/random.md b/wiki/cpp-tutorial/random.md index 6fb5223..f86d53a 100644 --- a/wiki/cpp-tutorial/random.md +++ b/wiki/cpp-tutorial/random.md @@ -1,7 +1,7 @@ --- bot_article: | # Generating Random Numbers in C++ -Simple example of random number generation in C++: + ## Simple example of random number generation in C++: ```cpp #include @@ -25,22 +25,28 @@ Simple example of random number generation in C++: # Generating Random Numbers A [Pseudorandom Number Generator (PRNG)](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) is an algorithm -for generating a sequence of (almost) random numbers. PRNGs maintain an internal state that is updated each time a new -number is generated. The initial state of the PRNG is called the seed and the process of setting the initial state is -called seeding. +for generating a sequence of numbers that appear random. PRNGs maintain an internal state that is updated each time a +new number is generated. The initial state of the PRNG is called the seed and the process of setting the initial state +is called seeding. The ability to generate the same sequence is important for replicating experiments. In the [C++ standard library](https://en.cppreference.com/w/cpp/header/random), random engines are callable objects that implement PRNG algorithms behind a [shared interface](https://en.cppreference.com/w/cpp/named_req/RandomNumberEngine.html). -Unlike the C `rand()` function, which relies on common shared seed via `srand()`, the C++ random engines are independent -and each one has its own seed. This ensures thread safety, whereas C `rand()` does not. Another thing worth mentioning -about `rand()` is that it is implementation defined and can vary system to system. The C++ random library should -always be preferred. +The C `rand()` function is a basic interface for generating random numbers, but the C standard does not specify what +random number generator should be used and does not guarantee any kind of statistical quality. Consequently it is often +implemented with a PRNG that has poor statistical properties. Unlike the C `rand()` function, which relies on a common +shared seed (and state) via `srand()`, the C++ random engines are independent and each maintains its own seed and +internal state. This allows each thread to be provided with its own instance of a random engine unlike in C. The C++ +random library should always be preferred. It should be noted that none of these PRNGs are cryptographically secure (should not be used for security-sensitive applications). This means that the state of the random engine can be figured out and predicted given enough values. +It should be noted that the common practice of using modulo `rand() % n` to change the distribution of generated numbers +creates a statistical bias (some numbers are more likely to appear than other). C++ solves this issue by introducing +utilities for changing random number distributions. + A common example of a random engine is `std::default_random_engine`, which serves as a standard, general-purpose generator. @@ -122,34 +128,6 @@ int main() { } ``` -## Seed Sequence - -Seed sequence (`std::seed_seq`) is a utility in the standard library for converting a small number of inputs into a -higher quality seed (does not contain large areas of zeros/ones) suitable for seeding PRNGs with large internal state -(e.g. `std::mt19937`). - -```cpp -#include -#include - -int main() { - // initialize seed sequence - std::seed_seq seq{1, 2, 3, 4}; - - // initialize Mersenne Twister engine with seed sequence - std::mt19937 gen{seq}; - - // initialize a uniform real distribution - std::uniform_real_distribution dis{0.0, 1.0}; - - // generate random numbers in the interval [0, 1) - for (int i = 0; i < 100; ++i) { - double random_number = dis(gen); - std::cout << random_number << std::endl; - } -} -``` - ## Linear Congruential Generator [Linear congruential generator (LCG)](https://en.wikipedia.org/wiki/Linear_congruential_generator) is a very simple PRNG @@ -166,20 +144,18 @@ considered fast but `minstd_rand0` and `minstd_rand` are not necessarily faster ## Predefined Generators -| Name | Generator | Summary | -| --------------------- | ------------------------- | -------------------------------------- | -| default_random_engine | implementation defined | Reproducibility is not important | -| minstd_rand0 | linear congruential | Small internal state | -| minstd_rand | linear congruential | Small internal state | -| mt19937 | mersenne twister | Generally should be preferred | -| mt19937_64 | mersenne twister | Generally should be preferred | -| ranlux24 | subtract with carry | Statistical quality | -| ranlux48 | subtract with carry | Statistical quality | -| knuth_b | minstd_rand0 with shuffle | Almost no reason to use it | -| philox4x32 (C++26) | counter-based philox | Good for multi-threaded applications\* | -| philox4x64 (C++26) | counter-based philox | Good for multi-threaded applications\* | - -\*Not yet implemented +| Name | Generator | +| --------------------- | ------------------------- | +| default_random_engine | implementation defined | +| minstd_rand0 | linear congruential | +| minstd_rand | linear congruential | +| mt19937 | mersenne twister | +| mt19937_64 | mersenne twister | +| ranlux24 | subtract with carry | +| ranlux48 | subtract with carry | +| knuth_b | minstd_rand0 with shuffle | +| philox4x32 (C++26) | counter-based philox | +| philox4x64 (C++26) | counter-based philox | [source](https://timsong-cpp.github.io/cppwp/n4868/rand.predef) From af1e8dc1212c69d125dd392b3e0499578da494e8 Mon Sep 17 00:00:00 2001 From: ProfessionalMenace Date: Fri, 3 Jul 2026 15:29:54 +0200 Subject: [PATCH 6/6] partial rewrite of the introduction --- wiki/cpp-tutorial/random.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/wiki/cpp-tutorial/random.md b/wiki/cpp-tutorial/random.md index f86d53a..c491943 100644 --- a/wiki/cpp-tutorial/random.md +++ b/wiki/cpp-tutorial/random.md @@ -26,26 +26,30 @@ bot_article: | A [Pseudorandom Number Generator (PRNG)](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) is an algorithm for generating a sequence of numbers that appear random. PRNGs maintain an internal state that is updated each time a -new number is generated. The initial state of the PRNG is called the seed and the process of setting the initial state -is called seeding. The ability to generate the same sequence is important for replicating experiments. +new number is generated. The initial state of the PRNG is called seed and the process of setting the initial state is +called seeding. The ability to generate the same sequence from the same seed is important for replicating experiments. In the [C++ standard library](https://en.cppreference.com/w/cpp/header/random), random engines are callable objects that implement PRNG algorithms behind a [shared interface](https://en.cppreference.com/w/cpp/named_req/RandomNumberEngine.html). The C `rand()` function is a basic interface for generating random numbers, but the C standard does not specify what -random number generator should be used and does not guarantee any kind of statistical quality. Consequently it is often -implemented with a PRNG that has poor statistical properties. Unlike the C `rand()` function, which relies on a common -shared seed (and state) via `srand()`, the C++ random engines are independent and each maintains its own seed and -internal state. This allows each thread to be provided with its own instance of a random engine unlike in C. The C++ -random library should always be preferred. +random number generator should be used and does not guarantee any kind of statistical quality. Consequently, it is often +implemented with a PRNG that has poor statistical properties. The C++ random library should always be preferred. It should be noted that none of these PRNGs are cryptographically secure (should not be used for security-sensitive applications). This means that the state of the random engine can be figured out and predicted given enough values. -It should be noted that the common practice of using modulo `rand() % n` to change the distribution of generated numbers -creates a statistical bias (some numbers are more likely to appear than other). C++ solves this issue by introducing -utilities for changing random number distributions. +Unlike the C `rand()` function, which relies on a common shared seed (and state) via `srand()`, the C++ random engines +are independent and each one maintains its own seed and internal state. Thread safety of `rand()` is not guaranteed and +it [may cause data race](https://eel.is/c++draft/rand#c.math.rand-3.sentence-2). The C++ random engines are both +guaranteed [thread safe](https://eel.is/c++draft/res.on.data.races#3) and each thread can be provided with its own +separate instance of a random engine. + +Using modulo `rand() % n` to change the distribution of generated numbers creates a statistical bias (some numbers are +more likely to appear than other). This is due to `RAND_MAX` (maximum possible value generated by `rand()`) not being +perfectly divisible by `n`. The C++ random library provides a whole range of utilities for correctly changing the random +number distributions. A common example of a random engine is `std::default_random_engine`, which serves as a standard, general-purpose generator.