Ok, to truly answer your question of IMO, just IMO, what is the safest way to generate random numbers:
1. Include
<random> and
<chrono>.
2. Create an instance of
std::default_random_engine:
std::default_random_engine URNG;
3. Create a seed sequence using
std::random_device and the system clock:
1 2 3 4
|
std::seed_seq::result_type seeds[] { std::random_device {}(),
std::seed_seq::result_type(std::chrono::system_clock::now().time_since_epoch().count()) };
std::seed_seq sseq(std::begin(seeds), std::end(seeds));
| |
4. Seed the engine:
URNG.seed(sseq);
You can seed the engine on creation, as long as you create the seed sequence first:
std::default_random_engine URNG(sseq);
Why use a seed sequence using
std::random_device and the system clock? To add a bit of randomness to the seed with each run, IF
std::random_device works. If it doesn't then seeding with the system clock works for most “casual, inexpert, and/or lightweight uses.”
5. Create a distribution that lets you create uniform integer or floating point (double) numbers:
1 2
|
std::uniform_int_distribution<int> idist(from, to);
std::uniform_real_distribution<double> ddist(from, to);
| |
For example, you want to roll a 6-sided die:
std::uniform_int_distribution<int> die(1, 6);
6. Obtain a random number using the distribution and the random engine:
int pip { die(URNG) };
You now have a random integer number between 1 & 6, inclusive.
Now, definitely this is not as easy to use as
rand/srand. Hide all these steps in a header-only file and that changes.
In my header file I added some basic error checking for the distributions where if the programmer enters wrong parameters, the first is higher than the second for example, it throws an error. And added some checks that prevent seeding the engine more than once won't happen, unless you force the seeding.