6

Currently, I have a main application in Fortran that need a seed to generate pseudo-random numbers. I would like to run many (many) times this application with completely uncorrelated seeds (and furthermore completely independent pseudo-random numbers chains).

My question is : how to generate the seeds with C++ 2011 ?

Vincent
  • 57,703
  • 61
  • 205
  • 388
  • I guess that numbers on single cored architecture would be pseudo-random, you would generate numbers like 1,2,3,4,5,6,7,8 and processes going sequentially via CPU would just took what's next and it'd act like `rand(); rand(); return rand();` – Vyktor Sep 07 '12 at 14:31

3 Answers3

7

In your main thread, extract a single seed (or seed sequence) from a good random source (e.g. from /dev/urandom on Linux). Use that data to seed a single root PRNG. Then use that PRNG to generate seed values for your thread-local PRNGs.

#include <random>
#include <vector>

typedef std::mt19937 rng_type;
std::uniform_int_distribution<rng_type::result_type> udist;

int main()
{
    rng_type rng;

    // seed rng first, and store the result in a log file:
    rng_type::result_type const root_seed = get_seed();
    rng.seed(root_seed);

    // make thread seeds:
    std::vector<rng_type::result_type> seeds(NUMBER_OF_THREADS);
    for (auto & n : seeds) { n = udist(rng); }

    // make threads...
}

The random number engine interface in <random> lets you seed both from a single integer and from a sequence of integers. If you want additional randomness, you can seed the mt19937 from a sequence of several hundred integers.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
7

C++11 provides std::random_device to provide non-deterministic random numbers if a source is available. You'll have to check your implementation to be sure it's good though. libc++ uses /dev/urandom by default. libstdc++ does as well if the macro _GLIBCXX_USE_RANDOM_TR1 is defined. Visual Studio's implementation is unfortunately not non-deterministic. edit: as of VS2012 their implementation uses Windows' cryptography services.

If std::random_device provides access to a non-deterministic source of randomness (typically /dev/urandom uses a cryptographic PRNG) then this should be sufficient for generating independent seeds.

#include <random>

int main() {
    std::random_device r;
    std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
    std::mt19937 engine(seed);

}

Instead of using a single value as a seed, some engines may do better with more seed data. A seed sequence is the alternative provided by the standard. Engines can be seeded with seed sequences, which are objects you load up with any amount of data and which produces seed data based on that.

std::random_device r;
std::vector<std::mt19937> engines;

int engines = 50;
for (int i = 0; i < engines; ++i) {
    std::seed_seq s{r(), r(), r(), r(), r(), r(), r(), r()};
    engines.emplace_back(s);
}

Eight 32-bit values, 256 bits, is enough but if you really want you can use more. Each of the standard engines documents how much data it uses from a seed sequence.

For example, each mt19937 engine will retrieve mt19937::state_size (624) 32-bit values from the seed sequence. The seeds retrieved from the seed sequence aren't the same as the input data, but they're based on that data, so we can use that much random data in the sequence.

std::random_device r;
std::vector<std::uint_least32_t> data;
std::generate_n(back_inserter(data), 624, std::ref(r));

std::seed_seq seed(begin(data), end(data));

std::mt19937 engine(seed); // 'fully' seeded mt19937
bames53
  • 86,085
  • 15
  • 179
  • 244
0

You can't ever really generate random seeds. You pull them from somewhere. The OS likely has a way to retrieve pseudorandom values (/dev/urandom on Linux, for example) which can be used to seed.

Getting a timestamp representing the current time is also a common option -- then to ensure you get different seeds for each thread, just make sure they ask for the timestamp at slightly different times, and use a high-resolution timer to ensure they actually get different values as seeds.

There's no "get a good seed" function built into C++11, because such a function is essentially meaningless. The computer can't generate random data. You have to pick something that looks random enough for your purposes, and use that to seed the random generator

jalf
  • 243,077
  • 51
  • 345
  • 550