Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using same random number generator across multiple functions

I am given to believe that random number generators (RNGs) should only be seeded once to ensure that the distribution of results is as intended.

I am writing a Monte Carlo simulation in C++ which consists of a main function ("A") calling another function ("B") several times, where a large quantity of random numbers is generated in B.

Currently, I am doing the following in B:

void B(){
    std::array<int, std::mt19937::state_size> seed_data;
    std::random_device r;

    std::generate(seed_data.begin(), seed_data.end(), std::ref(r));
    std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); //perform warmup
    std::mt19937 eng(seq);

    std::uniform_real_distribution<> randU(0,1);

    double myRandNum = randU(eng);

    //do stuff with my random number
}

As you can see, I am creating a new random number generator each time I call the function B. This, as far as I can see, is a waste of time - the RNG can still generate a lot more random numbers!

I have experimented with making "eng" extern but this generates an error using g++:

error: ‘eng’ has both ‘extern’ and initializer extern std::mt19937 eng(seq);

How can I make the random number generator "global" so that I can use it many times?

like image 374
GnomeSort Avatar asked Nov 26 '15 03:11

GnomeSort


1 Answers

Be careful with one-size-fits-all rules. 'Globals are evil' is one of them. A RNG should be a global object. (Caveat: each thread should get its own RNG!) I tend to wrap mine in a singleton map, but simply seeding and warming one up at the beginning of main() suffices:

std::mt19937 rng;

int main()
{
  // (seed global object 'rng' here)
  rng.dispose(10000); // warm it up

For your usage scenario (generating multiple RNs per call), you shouldn't have any problem creating a local distribution for each function call.

One other thing: std::random_device is not your friend -- it can throw at any time for all kinds of stupid reasons. Make sure to wrap it up in a try..catch block. Or, and I recommend this, use a platform specific way to get a true random number. (On Windows, use the Crypto API. On everything else, use /dev/urandom/.)

Hope this helps.

like image 60
Dúthomhas Avatar answered Sep 23 '22 14:09

Dúthomhas