How Does Calling Srand More Than Once Affect the Quality of Randomness

Calling srand() twice in the same program

It depends on how you call it. The purpose of srand() is to seed the pseudo-random number generator used by rand(). So when you call srand(i), it will initialise rand() to a fixed sequence which depends on i. So when you re-seed with the same seed, you start getting the same sequence.

The most common use case is to seed the generator just once, and with a suitable "random" value (such as the idiomatic time(NULL)). This guarantees makes it likely that you'll get different sequences of pseudo-random numbers in different program executions.

However, occasionally you might want to make the pseudo-random sequence "replayable." Imagine you're testing several sorting algorithms on random data. To get fair comparisons, you should test each algorithm on the exact same data - so you'll re-seed the generator with the same seed before each run.

In other words: if you want the numbers simply pseudo-random, seed once, and with a value as random as possible. If you want some control & replayability, seed as necessary.

Usefulness of `rand()` - or who should call `srand()`?

Use the new <random> header instead. It allows for multiple engine instances, using different algorithms and more importantly for you, independent seeds.

[edit]
To answer the "useful" part, rand generates random numbers. That's what it's good for. If you need fine-grained control, including reproducibility, you should not only have a known seed but a known algorithm. srand at best gives you a fixed seed, so that's not a complete solution anyway.

Why do I always get the same sequence of random numbers with rand()?

You have to seed it. Seeding it with the time is a good idea:

srand()

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main ()
{
srand ( time(NULL) );
printf ("Random Number: %d\n", rand() %100);
return 0;
}

You get the same sequence because rand() is automatically seeded with the a value of 1 if you do not call srand().

Edit

Due to comments

rand() will return a number between 0 and RAND_MAX (defined in the standard library). Using the modulo operator (%) gives the remainder of the division rand() / 100. This will force the random number to be within the range 0-99. For example, to get a random number in the range of 0-999 we would apply rand() % 1000.

Recommended way to initialize srand?

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

But if we are talking about rand() and srand()
The best simplest 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 the 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 the 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.
}


Related Topics



Leave a reply



Submit