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..c491943 --- /dev/null +++ b/wiki/cpp-tutorial/random.md @@ -0,0 +1,183 @@ +--- +bot_article: | + # Generating Random Numbers in C++ + ## Simple example of random number generation in C++: + + ```cpp + #include + #include + int main() { + 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 << dist(rng) << ' '; + } + } + ``` + + ## 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 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 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. 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. + +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. + +## 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 +#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) << ' '; + } +} +``` + +## 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). + +The random device should primarily be used for seeding random engines as it is slow and usually requires system calls. + +## Mersenne Twister + +[Mersenne Twister (MT)](https://en.wikipedia.org/wiki/Mersenne_Twister) is a general-purpose PRNG with good statistical +properties and a very fast speed. + +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). + +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. + +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 it less suitable for multi-threaded applications than other +PRNGs with a smaller state. + +```cpp +#include +#include + +int main() { + // 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) { + std::cout << dis(gen) << std::endl; + } +} +``` + +## Linear Congruential Generator + +[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. + +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). + +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. + +## 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) + +## 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..0003f93 100644 --- a/wiki/cpp-tutorial/sidebar.ts +++ b/wiki/cpp-tutorial/sidebar.ts @@ -171,6 +171,10 @@ const sidebar = [ ], collapsed: true, }, + { + text: "Random", + link: "/cpp-tutorial/random", + }, ], }, ];