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?
When you use statistical software to generate random numbers, you usually have an option to specify a random number seed. A seed is a positive integer that initializes a random-number generator (technically, a pseudorandom-number generator). A seed enables you to create reproducible streams of random numbers.
srand() uses its argument seed as a seed for a new sequence of pseudo-random numbers to be returned by subsequent calls to rand(). If srand() is not called, the rand() seed is set as if srand(1) was called at program start. Any other value for seed sets the generator to a different starting point.
The rand() function in C++ is used to generate random numbers; it will generate the same number every time we run the program. In order to seed the rand() function, srand(unsigned int seed) is used. The srand() function sets the initial point for generating the pseudo-random numbers.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With