Since c++11, the library for random number generation and distribution <random>
was introduced to solve this big hole that existed in c++ previously, as you have already noticed. cppreference has a translated version (mostly automatically) for English, just put pt.
in place of en.
on the link: <random>
in Portuguese. It’s a little outdated, but it should help. The English page is complete, however.
Anyway, let’s go to the code dissection now:
std::random_device r;
std::default_random_engine e1(r());
std::uniform_int_distribution<int> uniform_dist(1, 100);
return uniform_dist(e1);
The first line builds a std::random_device
, a non-deterministic random number generator1 (that is, it would be a true random number generator, not pseudorandom). This is one of several generators that exist in the standard library. The basic use of this generator is to call the function call operator operator()
to generate the next random number and advance the generator state:
std::random_device rd;
auto N = rd(); // N contém o número aleatório gerado por rd()
In the case of std::random_device
, the source of entropy does not come from a seed. In some implementations, such as the libc++ and the libstdc++, the standard entropy source is /dev/urandom
on Unix-like systems, rather than a seed. Other generators (of pseudorandom numbers) in the standard library accept a seed as an entropy source, which may be the case with std::default_random_engine
.
std::default_random_engine
may not be equal between implementations, since your engine is left as implementation-defined (that is, at the discretion of the implementation). The only recommended requirements are that the selection of that engine provides at least, acceptable behaviour for relatively casual, inexperienced and/or light use. The engine std::linear_congruential_engine
is usually used with some specific parameters to define the std::default_random_engine
.
Going back to the code:
std::default_random_engine e1(r());
This line builds a pseudorandom number engine (defined by the implementation) with a seed, whose number is generated by r()
, as a source of entropy. That is, the engine r
was used only to generate the seed of another engine e1
. Since this code was taken from within a function, this type of tactic is not good, since always when calling the function gerar_aleatorio()
, two engines will be built, one of them sown and only the first generation of number is performed. The most correct would be to use a single engine built for the entire program and use some distributor (such as the std::uniform_int_distribution
in this case) to generate the random numbers. Another solution is to do the e1
was thread_local
, so your startup is done only once for each thread.
Going to the next line in the code, we have:
std::uniform_int_distribution<int> uniform_dist(1, 100);
This distribution is one of several others in the standard library. Random number distributors post-process the number generated by a random number engine so that the result is distributed according to a given statistical probability density function. In other words, the result of a distributor follows a statistical standard. Specifically, the distributor std::uniform_int_distribution
produces a number that follows a uniform distribution (i.e., each number in the range will have almost the same amount of times generated statistically). This interval is given by constructing it through the constructor’s parameters (in the case of its code, this interval is [1, 100]
inclusive).
Finally, the last line:
return uniform_dist(e1);
The distributor of uniform_dist
has a operator()
similar to an engine: each call generates the next random number and updates/advances the state of the engine/distributor. The difference is that, in the case of the distributor, it receives as a parameter a random number engine. As stated before, this is necessary as a distributor only applies a density function on the random number generated by an engine. Who actually generates the random number is the engine, whereas the distributor only makes use of this output. The result of uniform_dist(e1)
state of the engine e1
and the distributor uniform_dist
and generates a pseudorandom number evenly distributed within the range [1, 100]
.
1 An implementation can define the generator std::random_device
in terms of a pseudorandom number generator if there is no non-deterministic source.
Excellent response. Remembering that
<random>
was introduced in C++11. For Jurassic versions of C++ a reliable alternative is the libraryBoost.Random
(I suspect that<random>
was heavily based on Boost).– Anthony Accioly
Man thank you very much! gave to understand line by line, just a doubt, has some engine that is more advisable to use?
– zaque
@Zaque for casual use,
std::default_random_engine
is enough. Read the descriptions of each engine in cppreference if you feel you have a specific case and an appropriate engine is needed.– Mário Feroldi