6

Before C++11, I used rand() from <cstdlib> and it was very simple to choose to seed (or not) the generator in the main() function (for example), then use in libraryA random numbers generated by a function somewhere in libraryB. The code looked like this:

LibraryB (generates random numbers, old-fashioned way):

#include <cstdlib> // rand, RAND_MAX
double GetRandDoubleBetween0And1() {
   return ((double)rand()) / ((double)RAND_MAX);
}

Main program:

#include <cstdlib> // srand
#include <ctime> // time, clock
int main() {
   bool iWantToSeed = true; // or false,
                            // decide HERE, applies everywhere!
   if(iWantToSeed){
      srand((unsigned)time(0) + (unsigned int)clock());
   }
   // (...)
}

LibraryA (uses random numbers from LibraryB, generated according to the seed given in main()):

#include "../folderOfLibraryB/Utils_random.h" // GetRandDoubleBetween0And1
void UseSomeRandomness(){
   for(int i = 0; i < 1000000; i++){
      double nb = GetRandDoubleBetween0And1();
      // (...)
   }
}

Easy, right?

Now I would like to update GetRandDoubleBetween0And1() using the C++11 standards available via #include <random>. I have already read and seen the examples here and there, but I don't see how to adapt it to my three modules. Surely, seeding the engine inside GetRandDoubleBetween0And1() is not the right thing to do...

Do you think I will have to pass the seeded engine from main() to UseSomeRandomness() in LibraryA, then from UseSomeRandomness() to GetRandDoubleBetween0And1() in LibraryB? Or is there a simpler way?

Georg
  • 1,078
  • 2
  • 9
  • 18

3 Answers3

5

Do you think I will have to pass the seeded engine from main() to UseSomeRandomness() in LibraryA, then from UseSomeRandomness() to GetRandDoubleBetween0And1() in LibraryB?

Yes.

You instantiate the generator once, then pass a reference or pointer to it into whatever contexts want to use it.

This is just like dealing with any other resource.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
4

You can do something like this:

#include <random>

inline double GetRandDoubleBetween0And1() {
    thread_local static std::mt19937 gen{std::random_device{}()};
    thread_local static std::uniform_real_distribution pick{0.0, 1.0};
    return pick(gen);
}

Being inline means you can put it in a header file and the compiler will create only one copy of the static objects which it will resolve at link time. However if you use it in a dynamic library you will get different copies. In that case you can put this function in its own library and link it to each program that uses the function.

The thread_local ensures thread safety (one random generator per thread) and being static they are only initialized once.

Galik
  • 47,303
  • 4
  • 80
  • 117
0

My 'random' library provide a high convenient wrapper around C++11 random classes. You can do almost all things with a simple 'get' method.

For your use case you can use auto seeded random_static wrapper with static API.

Examples:

#include "effolkronium/random.hpp"

using Random = effolkronium::random_static;

auto Func( ) { 
   return Random::get(-10, 10 )
}

auto Func2( ) { 
   return Random::get(-10, 10 )
}

int main( ) {
    // Seed static internal engine
    Random::seed( MySuperSeed );

}

It is single header-only library.

Check out the github page: https://github.com/effolkronium/random

effolkronium
  • 523
  • 4
  • 10