Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

generating random numbers in C++ using TR1 /dev/random (resilient to <1 second runs)

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; 
} 
like image 605
gnychis Avatar asked Dec 28 '11 20:12

gnychis


People also ask

How do you generate a random number between 1 and 10 in C?

In this program we call the srand () function with the system clock, to initiate the process of generating random numbers. And the rand () function is called with module 10 operator to generate the random numbers between 1 to 10. srand(time(0)); // Initialize random number generator.

How do you generate a random number between 1 and 6 in C++?

rand() is used to generate a series of random numbers. We use this function when we want to generate a random number in our code. Like we are making a game of ludo in C++ and we have to generate any random number between 1 and 6 so we can use rand() to generate a random number.

How do you get a random number between 0 and 1 in C++?

C++ Random Number Between 0 And 1 We can use srand () and rand () function to generate random numbers between 0 and 1. Note that we have to cast the output of rand () function to the decimal value either float or double.


2 Answers

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.

like image 77
Mysticial Avatar answered Oct 13 '22 03:10

Mysticial


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.

like image 30
Jeffrey Yasskin Avatar answered Oct 13 '22 01:10

Jeffrey Yasskin