Doubt with Random in c++14 and 17

Asked

Viewed 607 times

3

I was searching the Internet for how to do pseudo-random numbers in c++ and all the examples I found were with the srand function, but in some places people said srand is from c, and c++ already has a better library for creating random numbers, I searched on the internet but in Portuguese I didn’t find anything about it, so I went in a c++ documentation and found this snippet of code

int gerar_aleatorio(){
    random_device r;
    default_random_engine e1(r());
    uniform_int_distribution<int> uniform_dist(1, 100);
    return uniform_dist(e1);
}

it worked, but I did not understand what he is doing in each line, I did a search but I do not find anything in pt, I would like to understand what is being done in each line.

1 answer

5


Since , the library for random number generation and distribution <random> was introduced to solve this big hole that existed in 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.

  • 1

    Excellent response. Remembering that <random> was introduced in C++11. For Jurassic versions of C++ a reliable alternative is the library Boost.Random (I suspect that <random> was heavily based on Boost).

  • 1

    Man thank you very much! gave to understand line by line, just a doubt, has some engine that is more advisable to use?

  • @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.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.