Recommended Way to Initialize Srand

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.
}

srand() — why call it only once?

That depends on what you are trying to achieve.

Randomization is performed as a function that has a starting value, namely the seed.

So, for the same seed, you will always get the same sequence of values.

If you try to set the seed every time you need a random value, and the seed is the same number, you will always get the same "random" value.

Seed is usually taken from the current time, which are the seconds, as in time(NULL), so if you always set the seed before taking the random number, you will get the same number as long as you call the srand/rand combo multiple times in the same second.

To avoid this problem, srand is set only once per application, because it is doubtful that two of the application instances will be initialized in the same second, so each instance will then have a different sequence of random numbers.

However, there is a slight possibility that you will run your app (especially if it's a short one, or a command line tool or something like that) many times in a second, then you will have to resort to some other way of choosing a seed (unless the same sequence in different application instances is ok by you). But like I said, that depends on your application context of usage.

Also, you may want to try to increase the precision to microseconds (minimizing the chance of the same seed), requires (sys/time.h):

struct timeval t1;
gettimeofday(&t1, NULL);
srand(t1.tv_usec * t1.tv_sec);

Two ways of initializing `rand()`

The exact type of std::time_t is unspecified. It is usually a signed integer. std::srand takes an unsigned (i.e. unsigned int) argument.

There is therefore a mismatch between the type returned by std::time and what std::srand expects. Depending on the exact type of std::time_t the compiler might silently convert it, but it might not.

For example on Windows using the Visual C++ compiler time returns a 64-bit integer. This can't readily be converted to unsigned int without loss of precision, which the compiler might (should? I don't remember) warn about.

Therefore the cast, to make sure the correct type is passed to std::srand.


As the difference in the argument passed to time, in C++ 0 has since before standardization been implicitly convertible to a null pointer. IIRC modern C (since C99?) does it as well, but it haven't always been the case. Therefore the symbolic constant NULL for null pointers in C, and the integer constant 0 in C++.

Note that since C++11 the recommended null pointer is nullptr.

C program - srand()

because the seed is bound into the time() which are seconds since unix epoch, basically you're giving it the same seed because the loop takes less than a second.

What you should do is get the time in microseconds. Take a look at gettimeofday() if you're coding for windows google microseconds win32 C, you mind need to convert it from double to integerso just do this (unsigned int)double * 100.0f;

How to initialize random without time

If the chip has ADCs, one option is to take advantage of noise picked up on the ADCs. Basically, you can take a few reads of the ADCs, then bitwise AND to keep the least significant bit. Then use the all of the least significant bits sampled to generate your seed.

How often should I call srand() in a C++ application?

If you have only a single thread, seed once. If you reseed often, you might actually break some of the statistical properties of the random numbers. If you have multiple threads, don't use rand at all, but rather something threadsafe like drand48_r, which lets you maintain a per-thread state (so you can seed once per thread).



Related Topics



Leave a reply



Submit