21

The problem

I need to produce the same (pseudo) random number sequence on different machines and compilers. If I use the same kernel, it seems that the implementetion of mersenne twister (MT) in g++ works well: regardless if I compile my program on a newer machine, with g++ 4.9 or 4.7, I get the same random numbers. But I get different ones if I use older kernel or if I change to Visual Studio's compiler. That's ok, because there's no gurantee that mersenne_twister_engine::seed sets the internal state to the same over different compilers.

What I've already tried

I tought that applying operator<< on the generator produces a unique result that can be used to set the generators on other machines with the operator>>, but in case of mt19937, it seems it is not working. To make it clear, on a computer A I had the code

mt19937 generator1A; uniform_int_distribution<int> distribution(0, 1000); cout << "Generating random numbers with seed 1000" << endl; generator1A.seed(1000); generator1A(); //to advance the state by one so operator>> will give a longer output; this is not necessary indeed ofstream test("testseed1000.txt"); test << generator1A << endl; for (int i = 0; i < 10; ++i) cout << distribution(generator1A) << endl; 

And it produces 252, 590, 893, ..., and a long file. I transfer the file to the other machine B, and run the following code:

mt19937 generator1B, generator2B; uniform_int_distribution<int> distribution(0, 1000); cout << "Generating random numbers with seed 1000, and with operator>>" << endl; generator2B.seed(1000); generator2B(); // to advance the state by one here as well ifstream test("testseed1000.txt"); test >> generator1B; cout << "************************" << endl; cout << generator1B << endl; cout << "************************" << endl; cout << "With seed\twith operator>>" << endl; for (int i = 0; i < 10; ++i) cout << distribution(generator2B) << "\t" << distribution(generator1B) << endl; 

And it produces

654 205 205 115 115 610 

The question

Can you give advices how to generate the same (pseudo) random numbers with at least VC++ on Windows and g++ on Debian and Ubuntu? I'd like to use std if it is possible and I wouldn't like to implement my own MT engine.

Notes:

  • creating millions of random numbers and then reading in is not a solution
  • I have to use MSVS for code developing and unix servers for simulation
  • other than MT engines are also welcomed but I prefer MT
7
  • Honestly, it makes me pretty happy to hear that random numbers aren't generated in the same order on different machines with the same seed. Commented Feb 19, 2015 at 13:43
  • 13
    @AndyG: It shouldn't. The whole point of a seed is to get a reproducible sequence. Commented Feb 19, 2015 at 13:44
  • @MikeSeymour: Point taken. I wouldn't be surprised, though, if the machines OP is working on are a mix of 32 and 64 bit, which IIRC can have an effect on PRNG. Commented Feb 19, 2015 at 13:49
  • 1
    Minor point: you forgot to step generator2B once after creation. (or you stepped generator1A on accident) Commented Feb 19, 2015 at 14:11
  • 1
    If you really need to be reproducible and portable, don't use any PRNG from the standard library--fo it yourself, or use a third-party library with source, like my own ojrandlib. Commented Feb 19, 2015 at 19:26

2 Answers 2

13

To remove a variable from the problem, try looking at the outputs from your random number engine, rather than feeding it into a distribution.

I just looked at a few documentation pages for uniform_int_distribution, and it does not give any statement about how the outputs from the uniform random number generator are used. I'm not sure what the standard says.

I predict that you are getting the same outputs from your mersenne twister, but you're feeding those outputs into two inequivalent implementations of uniform_int_distribution.

If this is true, then to get the same random number sequence, you're going to have to use an external implementation of the distribution functions to ensure that you get the same results on all systems.

Sign up to request clarification or add additional context in comments.

1 Comment

You are right. Especially it is not needed to advance the internal state as I did but starting from the same seed number produces simply the same result. But now I have implement the distributions? Well, it is still easier than implementing a PRNG :)
11

The standard requires the engines to produce reproducible numbers across implementations, by specifying the value a default-constructed engine must produce on the 10000th invocation (it also specifies the actual transition and generation algorithms for the engines). For instance, for mt19937 the standard specifies that ([rand.predef]/p3):

typedef mersenne_twister_engine<uint_fast32_t, 32,624,397,31,0x9908b0df,11,0xffffffff,7,0x9d2c5680,15,0xefc60000,18,1812433253> mt19937; 

Required behavior: The 10000th consecutive invocation of a default-constructed object of type mt19937 shall produce the value 4123659995.

For distributions, there's no such requirement; instead the standard says that ([rand.dist.general]/p3):

The algorithms for producing each of the specified distributions are implementation-defined.

In other words, implementations may use different algorithms for the distributions, but must document the algorithms they use. MSVC and libstdc++ presumably use different algorithms.

You might consider using an external implementation, such as Boost.Random's distribution classes, if you want full portability.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.