Question

I would like to generate uniform random numbers in C++ between 0 and 1, in a way which does not use the standard rand() and srand(time(NULL)) method. The reason for this is that if I run the application more than once within the same second of my clock, the seed will be exactly the same and produce the same output.

I do not want to rely on boost or OS/compiler specifics. x86 can be assumed.

It seems as though an alternate way to do this is to use TR1 (I do not have C++11) and seeding with /dev/random in some way?

Right now I have this, but it still uses time(NULL) as a seed which will not work well within 1 second runs:

#include <iostream> 
#include <tr1/random> 

int main() 
{ 
  std::tr1::mt19937 eng; 
  eng.seed(time(NULL)); 
  std::tr1::uniform_int<int> unif(1, RAND_MAX); 
  int u = unif(eng); 
  std::cout << (float)u/RAND_MAX << std::endl; 
} 
Was it helpful?

Solution

Posting at request of the OP:

This is still somewhat compiler-specific, but will still work on nearly all x86-targeting compilers:

#ifdef _WIN32

//  Windows
#define rdtsc  __rdtsc

#else

//  For everything else
unsigned long long rdtsc(){
    unsigned int lo,hi;
    __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
    return ((unsigned long long)hi << 32) | lo;
}

#endif

int main() 
{ 
  std::tr1::mt19937 eng; 
  eng.seed( rdtsc() );    //  Seed with rdtsc.
  std::tr1::uniform_int<int> unif(1, RAND_MAX); 
  int u = unif(eng); 
  std::cout << (float)u/RAND_MAX << std::endl; 
} 

The idea here is to seed your random number generator with the rdtsc cycle-counter.

The reason why this works is because the rdtsc cycle-counter iterates at about (often the same) speed as the CPU frequency. Therefore, the chances of two calls to it returning the same value are extremely slim - thereby, making it an excellent seed for a RNG.

OTHER TIPS

TR1 in [tr.rand.device] specifies a random_device class that generates unsigned ints from an implementation-dependent source. So the following should work, although I haven't compiled it myself:

int main() {
  std::tr1::random_device dev_random;
  std::tr1::mt19937 eng(dev_random());
  ...

In TR1, passing dev_random directly without calling it works and initializes eng's state more randomly, but in C++11 you have to wrap seed arguments into another class. Since calling the argument works in both libraries, I'd do that for maintainability, unless you have more demanding needs.

Your problem is related to the way you seed the random number generator. Obviously seeding with time(NULL) is going to produce the same PRNG sequence within that second when seeded. This is the most common way to seed rand, but is unfortunately bad practice because of this very issue. Not only that, I have read that it can cause bias in the results.

Note that EVERY PRNG will produce the same result if seeded with the same values. So your problem is not related to the generator, more to seeding.

I asked a question about seeding on here just a few weeks back and was given a link to the following article which you may also find useful. Good Practice in (Pseudo) Random Number Generation for Bioinformatics Applications See the section on seeding or warming up the generator.

rand() is not the best random number generator, but is suitable in many cases provided it is properly seeded. If you want something better where the repeat sequence is very large then there are some provided in that link. Or use the TR1 based ones. Personally, I'd go with more portable C++03 based code and steer clear of TR1.

Also consider Multiply with carry as an alternative PRNG algorithm.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top