-
Notifications
You must be signed in to change notification settings - Fork 20
Random number generation - merging bot articles #79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ProfessionalMenace
wants to merge
7
commits into
TCCPP:main
Choose a base branch
from
ProfessionalMenace:random
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
ce29b3e
C++ PRNG article
ProfessionalMenace 1fe1e92
Typos
ProfessionalMenace 0c3a8f1
beginnerification
ProfessionalMenace d9e8a7b
Merge branch 'TCCPP:main' into random
ProfessionalMenace 9ef1958
Apply suggestions from code review
ProfessionalMenace 8c0d0d5
applied suggestions
ProfessionalMenace af1e8dc
partial rewrite of the introduction
ProfessionalMenace File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,183 @@ | ||
| --- | ||
| bot_article: | | ||
| # Generating Random Numbers in C++ | ||
| ## Simple example of random number generation in C++: | ||
|
|
||
| ```cpp | ||
| #include <random> | ||
| #include <iostream> | ||
| int main() { | ||
| std::random_device dev; // for seeding | ||
| std::default_random_engine rng{dev()}; | ||
| std::uniform_int_distribution<int> 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 | ||
|
ProfessionalMenace marked this conversation as resolved.
|
||
| 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 `<random>` 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 <random> | ||
| #include <iostream> | ||
|
|
||
| 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<int> 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 <iostream> | ||
| #include <random> | ||
|
|
||
| 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<double> 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/)** | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.