Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recommended way to initialize srand?

Tags:

c++

random

srand

I need a 'good' way to initialize the pseudo-random number generator in C++. I've found an article that states:

In order to generate random-like numbers, srand is usually initialized to some distinctive value, like those related with the execution time. For example, the value returned by the function time (declared in header ctime) is different each second, which is distinctive enough for most randoming needs.

Unixtime isn't distinctive enough for my application. What's a better way to initialize this? Bonus points if it's portable, but the code will primarily be running on Linux hosts.

I was thinking of doing some pid/unixtime math to get an int, or possibly reading data from /dev/urandom.

Thanks!

EDIT

Yes, I am actually starting my application multiple times a second and I've run into collisions.

like image 827
Gary Richardson Avatar asked Nov 27 '08 04:11

Gary Richardson


People also ask

Why do you need Srand () when getting a random number?

The generation of the pseudo-random number depends on the seed. If you don't provide a different value as seed, you'll get the same random number on every invocation(s) of your application. That's why, the srand() is used to randomize the seed itself.

How do you call a Srand in C++?

srand() sets the seed which is used by rand to generate “random” numbers. If you don't call srand before your first call to rand, it's as if you had called srand(1) to set the seed to one. In short, srand() — Set Seed for rand() Function.

How do you get Srand seeds?

rand() does not offer any way to extract or duplicate the seed. The best you can do is store the initial value of the seed when you set it with srand() , and then reconstruct the whole sequence from that. The Posix function rand_r() gives you control of the seed.

What does Srand time 0 )) do?

Using the time as a seed - srand(time(0)) at the beginning of the program to initialize the random seed. time(0) returns the integer number of seconds from the system clock.


2 Answers

This is what I've used for small command line programs that can be run frequently (multiple times a second):

unsigned long seed = mix(clock(), time(NULL), getpid()); 

Where mix is:

// Robert Jenkins' 96 bit Mix Function unsigned long mix(unsigned long a, unsigned long b, unsigned long c) {     a=a-b;  a=a-c;  a=a^(c >> 13);     b=b-c;  b=b-a;  b=b^(a << 8);     c=c-a;  c=c-b;  c=c^(b >> 13);     a=a-b;  a=a-c;  a=a^(c >> 12);     b=b-c;  b=b-a;  b=b^(a << 16);     c=c-a;  c=c-b;  c=c^(b >> 5);     a=a-b;  a=a-c;  a=a^(c >> 3);     b=b-c;  b=b-a;  b=b^(a << 10);     c=c-a;  c=c-b;  c=c^(b >> 15);     return c; } 
like image 198
Jonathan Wright Avatar answered Sep 21 '22 15:09

Jonathan Wright


The best answer is to <random>. If you are using a pre C++11 version you can alternatively look at Boost random number stuff.

But if we are talking about rand() and srand()
The best simplist way is just to use time():

int main() {     srand(time(nullptr));      ... } 

Be sure to do this at the beginning of your program, and not every time you call rand()!


Side Note:

NOTE: There is a discussion in the comments below about this being insecure (which is true, but ultimately not relevant (read on)). So an alternative is to seed from the random device /dev/random (or some other secure real(er) random number generator). BUT: Don't let this lull you into a false sense of security. This is rand() we are using. Even if you seed it with a brilliantly generated seed it is still predictable (if you have any value you can predict the full sequence of next values). This is only useful for generating "pseudo" random values.

If you want "secure" you should probably be using <random> (Though I would do some more reading on a security informed site). See the answer below as a starting point: https://stackoverflow.com/a/29190957/14065 for a better answer.

Secondary note: Using random device actually solves the issues with starting multiple copies per second better than my original suggestion below (just not the security issue).


Back to original story:

Every time you start up, time() will return a unique value (unless you start the application multiple times a second). In 32 bit systems, it will only repeat every 60 years or so.

I know you don't think time is unique enough but I find that hard to believe. But I have been known to be wrong.

If you are starting a lot of copies of your application simultaneously you could use a timer with a finer resolution. But then you run the risk of a shorter time period before the value repeats.

OK, so if you really think you are starting multiple applications a second.
Then use a finer grain on the timer.

 int main()  {      struct timeval time;       gettimeofday(&time,NULL);       // microsecond has 1 000 000      // Assuming you did not need quite that accuracy      // Also do not assume the system clock has that accuracy.      srand((time.tv_sec * 1000) + (time.tv_usec / 1000));       // The trouble here is that the seed will repeat every      // 24 days or so.       // If you use 100 (rather than 1000) the seed repeats every 248 days.       // Do not make the MISTAKE of using just the tv_usec      // This will mean your seed repeats every second.  } 
like image 41
Martin York Avatar answered Sep 21 '22 15:09

Martin York