Recently I was trying out a program on generating random numbers in C++ using the random engines
defined in #include
. My program goes
One important thing to know about pseudo random number generators is that they produce a sequence of numbers, and 'randomness' is a quality that the sequence is tested for. That is, you can't say that a particular number is random or not (is '4' a random number?). You instead say whether the sequence of numbers is random or not.
When you "seed" a pRNG you are generally selecting one of the sequences it can generate, and those numbers are random with respect to the rest of the sequence. So in general if you want 'randomness' you want to first select a particular sequence and then to use successive numbers from that particular random sequence.
In your code without static
, you're selecting a sequence on each iteration of the loop, and then using one number from that sequence. Since you're not using many values from the same sequence it's not really much surprise that the result doesn't look random.
When you add static
the engine is no longer being seeded on each iteration of the loop. Instead it's seeded once and each iteration of the loop uses successive values from that sequence, just like you're supposed to do. And this is what static
means on block scoped variables: it means that the variable lives externally to the block it's declared in and that it will only be initialized the first time.
static
does fix your problem, however I would argue that it's not a good solution. static
variables have some similarities to global variables and cause some of the same problems. Instead what I would recommend is for you to explicitly move the engine outside the loop. For example:
int random (int lim, default_random_engine &dre)
{
uniform_int_distribution<> uid(1,lim);
return uid(dre);
}
int main()
{
default_random_engine dre (chrono::steady_clock::now().time_since_epoch().count());
for (int i = 0; i < 10; ++i)
{
cout << random(100, dre) << " ";
}
}
Now the state is being explicitly managed and passed into the random()
function, which is better than relying on the hidden and implicit behavior of a block scoped static
variable.
Also in general I would not recommend using time as a sole source of seed data. A low resolution clock might not provide new seeds frequently enough, and the program being run in different places at the same time can use the same seed.
My recommendation for seeding is:
std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 eng(seed);
(There's no need for beginners to know what mt19937 or any of the other bits are about. They just need to know to paste this at the appropriate location and how to use eng
. In your code you'd need to replace each use of default_random_engine
with mt19937
.)