4

Summary: I need a simple self-contained way to seed my RNG so that the seed is different every time the program is launched.

Details:

I often need to run the same program (which does calculations with random numbers, e.g. Monte Carlo simulation etc.) many times to have good statistics on the result. In this case it is important that the random number generator will have a different seed on each run.

I would like to have a simple, cross-platform solution for this that can be contained within the program itself. (I.e. I don't want to always go to the trouble of having a script that launches each instance of the program with a different seed parameter.)

Note that using time(0) as a seed is not a good solution because the timer resolution is bad: if several processes are launched in parallel, they are likely to get the same seed from time(0).

Requirements:

  • as simple as possible
  • cross platform (currently I need it to work on Windows & Linux, x86 & x64 only).
  • self contained: shouldn't rely on a special way of launching the program (passing the seed as a parameter from the launch script is too much trouble).
  • I'd like to wrap the whole thing into a small library that I can include in any new project with minimal effort and just do something like SeedMyRNG(getSeed());

EDIT:

Although my main question was about doing this in C (or C++), based on the pointers provided in the answer I found os.urandom() as a Python solution (which is also useful for me).

Related relevant question: How to use /dev/random or urandom in C?

Community
  • 1
  • 1
Szabolcs
  • 24,728
  • 9
  • 85
  • 174
  • Why not combine `time(0)` with a process id? – sharptooth Jul 27 '11 at 12:54
  • @sharptooth Using the PID was one idea before I posted here, but I like the solutions from the answers much better. The purpose of those RNGs built into to OSs seems to be exactly to get numbers that are random even across machines. I still wonder if after turning on a computer cluster (using a single switch) the program might get the same PID on the different nodes (since they have the same software, disk content etc. and were booted up at the same time). – Szabolcs Jul 27 '11 at 13:19
  • Sure, using secure seeding is better, but if you need a fallback, then `time(0) + getpid()` is better than time alone. Note that `time(0) ^ getpid()` might be worse (imagine one process started each second; it all may cancel out). In theory, the seed for `/dev/urandom` is totally unpredictable, so it can't be the same on two nodes; nearly everything the computer does, goes in. If there's any user interaction (keyboard, mouse), then it works well. – maaartinus Aug 08 '14 at 03:03

4 Answers4

4

"Cross-platform" is a subjective term. Do you mean "any platform" (you might encounter in the future) or "every platform" (on your list of supported platforms)? Here's a pragmatic approach that I usually take:

  1. Check if you have /dev/urandom; if yes, seed from there.

  2. On Windows, use CryptGenRandom().

  3. If all else fails, seed from time().

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • I'm making a comment because of the limited durability of the link: [My implementation](http://pastebin.com/f67tVQJw) of the above. – Kerrek SB Jul 27 '11 at 12:56
  • I read about `/dev/random` a bit on Wikipedia and it seems to be very common on different unixes. Is there a similarly common C function to avoid having to do file operations and checking if they succeed? Also thanks for the code!! – Szabolcs Jul 27 '11 at 13:01
  • What's the difference between `/dev/urandom` and `/dev/random`? – Szabolcs Jul 27 '11 at 13:01
  • Reading from `urandom` never blocks. By contrast, if `random` is depleted, the read call will block until enough random bytes are available. Also, there is no standard C function - OS-based entropy collection is extremely far from the scope of the C language! – Kerrek SB Jul 27 '11 at 13:02
1

You could use dev random on Linux and the crypto api on Windows. Write a small library to present a platform independent interface and it should do exactly what you want.

Szabolcs
  • 24,728
  • 9
  • 85
  • 174
asm
  • 8,758
  • 3
  • 27
  • 48
  • Thanks for the edit, I was on my tablet and couldn't remember the correct formatting. The mobile version of SO doesn't seem to have the helpers that the desktop version does. – asm Jul 27 '11 at 21:13
1

Check out RandomLib which is a C++ random number library with good support for seeds. In particular

Random r;
r.Reseed();

causes r to be seeded with a vector of numbers (from a call to RandomSeed::SeedVector()) which is almost certainly unique. This includes the time, microseconds, pid, hostid, year.

Less optimally, you can also seed with RandomSeed::SeedWord() which reads from /dev/urandom if possible. However, you will typically get a seed collision after 2^16 runs with a single 32-bit word as your seed. So, if your application is run many times, you are better off using the bigger seed space offered by a vector.

Of course, this supposes that you are using a random number generator that can make use of a vector seed. RandomLib offers MT19937 and SFMT19937, which both use vector seeds.

cffk
  • 1,839
  • 1
  • 12
  • 17
0

Update on 2014-08-04:

Boost has a cross-platform implementation now, random_device. Here's an example for seeding a pseudo-random generator from boost using an unpredictable seed:

#include <boost/random/mersenne_twister.hpp>
#include <boost/random/random_device.hpp>

boost::random::mt11213b rng( (boost::random_device())() );
Szabolcs
  • 24,728
  • 9
  • 85
  • 174