I have a C++11 program that needs to create several independent random generators, for use by different threads in a parallel computation. These generators should be initialized with different seed values so that they all produce different pseudo-random sequences.
I see that there's a std::seed_seq
class that seems to be meant for this purpose, but it's not clear what's the right way to construct one. The examples I've seen, such as the one on cppreference.com, initialize it with a handful of integer constants hard-coded in the program:
std::seed_seq seq{1,2,3,4,5};
I doubt that's actually a recommended best practice, so I'm wondering what is the recommended practice. In particular:
seed_seq
can be initialized with an arbitrary number of integers, what's the significance of the length of its initializer list? If I want to produce seeds for 100 random generators, do I need to initialize my seed_seq
with 100 integers?seed_seq
with just one integer and then use it to produce a large number of seeds?seed_seq
from a single integer and then generate lots of seeds from it, what's the benefit of using seed_seq
instead of an ordinary random generator? Why not just construct a std::mt19937
from that single integer and use that to produce seed values for other generators?The trouble with using a fixed sequence like that is that you get the same sequence of seeds out of it, much the same as if you had called srand(42)
at the start of your program: it generates identical sequences.
The C++11 standard states (in section 26.5.7.1 Class seed_seq
):
A seed sequence is an object that consumes a sequence of integer-valued data and produces a requested number of unsigned integer values i, 0 i < 232, based on the consumed data.
[Note: Such an object provides a mechanism to avoid replication of streams of random variates. This can be useful, for example, in applications requiring large numbers of random number engines. —end note]
It also states how those integers are turned into seeds in paragraph 8
of that section, in such a way that the distribution of those seeds is acceptable even if the integer input items are very similar. So you can probably think of it as a pseudo-random number generator for seed values.
A larger number of items will provide more "randomness" in the seed values, provided they have some randomness themselves. Using constants as input is a bad idea for this reason.
What I tend to do is very similar to the way you normally randomise one generator, with srand (time (0))
. In other words:
#include <random>
#include <cstdint>
#include <ctime>
#include <iostream>
int main()
{
std::seed_seq seq{time(0)};
std::vector<std::uint32_t> seeds(10);
seq.generate(seeds.begin(), seeds.end());
for (std::uint32_t n : seeds) {
std::cout << n << '\n';
}
}
If you have multiple sources of randomness, such as a value read from /dev/random
under Linux, or a white noise generator of some description, or the average number of milliseconds between keypresses the last time a user ran this program, you could use those as extra inputs:
std::seed_seq seq{time(0), valFromDevRandom(), getWhiteNoise(), avgMillis()};
but I doubt constants are the way to go, since they add no randomness to the equation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With