for my program I need pseudo random integers with different ranges. Until now I used the rand() function but it has it's limitations.
I found the boost::random library to be a much better replacement but I didn't want to create random generators all over the place.
( I need random integers in many classes, because it's a stress test software that makes every decision pseudo-randomly ( -> a test run has to be repeatable by setting the same start seed ) ).
That's why I capsuled boost::random away in my own class.
The idea behind this is to ease the use so that it is almost as straightforward as the C++ rand() method
#include "boost/shared_ptr.hpp"
#include "boost/random.hpp"
class Random{
public:
typedef boost::shared_ptr< Random > randomPtr;
typedef boost::mt19937 randomGeneratorType;
static randomPtr Get(){
static randomPtr randomGen( new RandomGenerator() );
return randomGen;
}
void SetSeed(int seed){
randomGenerator.seed( seed );
}
int Random( int lowerLimit, int upperLimit ){
boost::uniform_int<> distribution( lowerLimit, upperLimit );
boost::variate_generator< randomGeneratorType&, boost::uniform_int<> >
LimitedInt( randomGenerator , distribution );
return LimitedInt();
}
private:
// prevent creation of more than one object of the LogManager class
// use the Get() method to get a shared_ptr to the object
Random():
randomGenerator() //initialize randomGenerator with default constructor
{}
RandomGenerator( const RandomGenerator& orig ){};
randomGeneratorType randomGenerator;
};
Generating a random number within a given range will now be as easy as
#include "Random.h"
Random::Get()->SetSeed( 123123 ); // If you want to make the run repeatable
int dice = Random::Get()->Random(1,6);
Question:
Is there anything wrong with this way of generating random numbers?
Large overhead I didn't recognize ?
Pure Evil or outdated programming technique ?
( I'm still new to c++ and want to improve my skills, and I have found that Stack overflow is the best place to get high quality advice )
Joe Gauterin demonstrated the issue, however it didn't offered any solution :)
The problem with shared state is the absence of reentrance: ie, executing twice the same method does not provide the same result. This is particularly critical in multithreaded situations because the global state may not always change at the same point in the program, thus leading to inconsistent results from one run to another.
The solution is that each simulation should have its own "state" and then you would avoid the shared state.
This can be accomplished in a number of ways: you could still use a "global" state but make it local to a thread, for example, thus the threads would not step on each others toes.
The cleaner version, however, consists in storing this state somewhere, and the easier way is to have some kind of Context
class, instantiated once per simulation, and which is an aggregate of the state of the simulation (for simulation-wide state).
With that in mind:
class Context
{
public:
typedef boost::mt19937 RandomGeneratorType;
void SetSeed(int seed){
rg.seed( seed );
}
int Next( int lowerLimit, int upperLimit ) {
boost::uniform_int<> distribution( lowerLimit, upperLimit );
boost::variate_generator< randomGeneratorType&, boost::uniform_int<> >
LimitedInt( rg, distribution );
return LimitedInt();
}
private:
RandomGeneratorType rg;
};
Then, pass the Context
instance around in your simulation, and you can run as many as you wish in parallel.