Professional C__ - Marc Gregoire [283]
The quality of a random number generator is referred to as its entropy measure. The entropy() method of the random_device class returns 0.0 if it is using a software-based pseudo-random number generator, and returns a nonzero value if there is a hardware device attached. The nonzero value is an estimate of the entropy of the attached device.
Using the random_device engine is rather straightforward:
random_device rnd;
cout << "Entropy: " << rnd.entropy() << endl;
cout << "Min value: " << rnd.min()
<< ", Max value: " << rnd.max() << endl;
cout << "Random number: " << rnd() << endl;
Code snippet from Random\random_device.cpp
A possible output of this program could be as follows:
Entropy: 32
Min value: 0, Max value: 4294967295
Random number: 3590924439
Next to the random_device engine, there are three pseudo-random number engines:
The linear congruential engine requires a minimal amount of memory to store its state. The state is a single integer containing the last generated random number or the initial seed if no random number has been generated yet. The period of this engine depends on an algorithmic parameter and can be up to 264 but usually less. For this reason, the linear congruential engine should not be used when you need a high-quality random number sequence.
From the three pseudo-random number engines, the Mersenne twister generates the highest quality of random numbers. The period of a Mersenne twister depends on an algorithmic parameter but is much bigger than the period of a linear congruential engine. The memory required to store the state of a Mersenne twister also depends on its parameters but is much higher than the single integer state of the linear congruential engine. For example, the predefined Mersenne twister mt19937 has a period of 219937−1, while the state contains 624 integers or around 2.5 kilobytes.
The subtract with carry engine requires a state of 25 integers or around 100 bytes, however, the quality of the generated random numbers is less than the numbers generated by the Mersenne twister.
The mathematical details of the engines fall outside the scope of this book, and defining the quality of random numbers requires a mathematical background. If you want to know more about this topic, you can consult a reference from the “Random Numbers” section in Appendix B.
The random_device engine is easy to use and doesn’t require any parameters. However, creating an instance of one of the three pseudo-random number generators requires you to specify a number of mathematical parameters, which can be complicated. The selection of parameters greatly influences the quality of the generated random numbers. For example, the definition of the mersenne_twister_engine class looks as follows:
template UIntType b, size_t t, UIntType c, size_t l, UIntType f> class mersenne_twister_engine {...} It requires 14 parameters. The linear_congruential_engine and the subtract_with_carry_engine classes also require a number of these mathematical parameters. For this reason, the standard defines a number of predefined engines. One example is the mt19937 Mersenne twister which is defined as follows: typedef mersenne_twister_engine 1812433253> mt19937; These parameters are all magic, unless you understand the details of the Mersenne twister algorithm. In general, you do not want to modify any of these parameters unless you are a specialist in the mathematics of pseudo-random number generators. Instead, it is highly recommended to use one of the predefined typedefs such as mt19937. A complete list of predefined engines is given in a later section. Random Number Engine Adapters A random number engine adapter modifies the result of a random number engine you associate it with, which is called the base engine.