Many people seed their Mersenne Twister engines like this:
std::mt19937 rng(std::random_device{}());
However, this only provides a single unsigned int
, i.e. 32 bits on most systems, of seed randomness, which seems quite tiny when compared to the 19937 bit state space we want to seed. Indeed, if I find out the first number generated, my PC (Intel i7-4790K) only needs about 10 minutes to search through all 32 bit numbers and find the used seed. (I know that MT is not a cryptographic RNG, but I just did that to get a feel for how small 32 bit really is in these days.)
I am trying to build a function to properly seed a mt19937
and came up with this:
#include <algorithm>
#include <iostream>
#include <random>
auto RandomlySeededMersenneTwister () {
// Magic number 624: The number of unsigned ints the MT uses as state
std::vector<unsigned int> random_data(624);
std::random_device source;
std::generate(begin(random_data), end(random_data), [&](){return source();});
std::seed_seq seeds(begin(random_data), end(random_data));
std::mt19937 seededEngine (seeds);
return seededEngine;
}
int main() {
auto rng = RandomlySeededMersenneTwister();
for (int i = 0; i < 10; ++i)
std::cout << rng() << "\n";
}
This does look like a safe solution to me; however, I have learned that problems with RNG are often times quite subtle.
Provided std::random_device
produces good, random data on my system, does the code give me a correctly seeded std::mt19937
?
std::random_device
does not work correctly on every platform (I'm looking at you MinGW). If you're going the Boost way, then you could useboost::random_device
instead. \$\endgroup\$std::mt19937 eng{boost::random_device{}}
(uses astd::seed_seq
as the device is fed) unlikestd::mt19937 eng{std::random_device{}()}
(mind the parenthesis; uses anunsigned
as just an unsigned integer is fed). Refer pcg-random.org's article. \$\endgroup\$