Why is it "bad" to call srand multiple times?

This topic is 1849 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

I keep reading this, but never an explanation. Being curious, I took a look at Visual Studio's code for rand and srand and all srand does is set a global variable. rand performs a typical pseudo-random number algorithm based on the global variable.

While I don't see any need to call srand multiple times, save for using the same seed to repeat the random values, I cannot see the harm. Why is it "bad"?

Share on other sites
What argument are you going to call it with next time? And why? If you want to make your rand sequence more random, throw away random numbers by calling rand() while waiting for something to happen you have no control over (such as a keypress).

Share on other sites
<blockquote class="ipsBlockquote" data-author="MarkS" data-cid="5014813"><p>I keep reading this, but never an explanation. Being curious, I took a look at Visual Studio's code for rand and srand and all srand does is set a global variable. rand performs a typical&nbsp;pseudo-random number algorithm based on the global variable.<br />&nbsp;<br />While I don't see any need to call srand multiple times, save for using the same seed to repeat the random values, I cannot see the harm. Why is it "bad"?</p></blockquote><br />because you normally pass a fairly low resolution timer value to srand, so if you do srand , rand, srand rand and both srand calls get passed the same value you will also get the same result from the rand calls. (which makes it very non random)

Share on other sites
What argument are you going to call it with next time? And why?

No idea. I'm not asking this because I plan on doing this or am currently doing this. I just want an explanation to go along with the statement.

Share on other sites
It's not necessarily calling srand multiple times, it's beginners repeatedly calling [tt]srand[/tt] with [tt]time(0)[/tt] and making a "rand isn't random" thread on gamedev:
for ( int i = 1; i <= 10; i=i+1 )
{
srand( time(0) );
int val = rand()%10 + 1;
cout << val << endl;
}

Edited by fastcall22

Share on other sites
Well, you can't call it with the return value from rand(), since it will be the same. And if you already seeded it with a timer, seeding it again soon afterwards is likely to be predictable too. Only call srand with a known value if you need to repeat a random sequence again.

EDIT: Which is incredibly useful e.g. for rerunning simulations or doing a replay playback when you only store keypresses. Edited by Paradigm Shifter

Share on other sites
The explanation is that that's not how you should use a pseudo-random number generator. The people that designed the PRNG expect you to seed it once and then extract many numbers from it. If you use it differently, you may get bad results, depending on the exact details of how you use it.

Share on other sites

I don't know the context in which you heard that re-using srand is bad, but if you understand that you don't have to re-seed all the time (usually never) then I think you probably understand what's going on and can do what you like.

Edited by Khatharr

Share on other sites
I keep reading this, but never an explanation. Being curious, I took a look at Visual Studio's code for rand and srand and all srand does is set a global variable. rand performs a typical pseudo-random number algorithm based on the global variable.

because you just don't need to do that, its like checking variable twice just to make sure its value is consistent. just do

// time() returns the time as the number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).
srand(time()); // well not sure time() is present in MSVC


Share on other sites
srand(time()); // well not sure time() is present in MSVC
Yes, time() is standard.

Share on other sites
Calling srand() multiple times is not "bad". If you need to call it multiple times then call it multiple times. There are many scenarios in which you would. You may for instance randomly generate game levels and want to save the seed that you used to randomly generate the levels as part of the game save file. In that case, you would call srand() every time you load a level.

The problem is that if you see someone calling srand() multiple times and that person is a beginner, generally speaking, they're doing so because they don't know what they are doing, so you see people saying, "Don't do that". That's all.

Share on other sites

Thanks, everyone.

Some of this I knew and some I didn't. However, every time a newbie would post code calling srand multiple times, they would be chastised, but rarely with explanation. This has the tendency to leave a new programmer in a state of confusion and with the feeling that they violated some unwritten rule. Hopefully this thread will be linked to in future cases.

Share on other sites
Good answer, apart from you kind of went off on one in the last paragraph ;)

Share on other sites

I did, didn't I?

I've been in that mood today, having to twice cancelled from posting fully-written very colorful and sarcastic responses to... less than helpful users, on another forum.

At least the above slightly sarcastic response wasn't directed at a specific individual.

Share on other sites
At least the above slightly sarcastic response wasn't directed at a specific individual.

It does sound suspiciously familiar...

Share on other sites

[quote name='Servant of the Lord' timestamp='1356642050' post='5014852']Don't use rand(), it's inaccurate after the 2 billionth number is generated, and certain values are more likely to come up with an 0.003% higher probability than others. Instead, forget about completing your stupid little project, and go look up real fake psuedonumericallyperfectrandom number generators that college students study in compute science class.
[/quote]

I feel hurt because this is actually very relevant to my work  nah no offense taken, it's true that for beginners it's best to just explain to them how to use those basic PRNG's, and then they can look up more about them if they're interested. In general, using rand() is perfectly fine for basically everything unless you're running a gambling site, ultra high precision probabilistic algorithm, cryptographic infrastructure, or other highly specialized tasks. Nothing like information overload to put somebody off programming.

Share on other sites

Don't use rand(), it's inaccurate after the 2 billionth number is generated, and certain values are more likely to come up with an 0.003% higher probability than others. Instead, forget about completing your stupid little project, and go look up real fake psuedonumericallyperfectrandom number generators that college students study in compute science class.

In general, using rand() is perfectly fine for basically everything unless you're running a gambling site, ultra high precision probabilistic algorithm, cryptographic infrastructure, or other highly specialized tasks. Nothing like information overload to put somebody off programming.

Using rand() is perfectly fine *if* you only need a uniform distribution. There are a lot of times where this isn't the case (for example, generating white noise, where you want a gaussian distribution). In those cases you'll need some kind of random number generator. I'd recommend the boost::random library, which lets you specify any distribution you want.

Also, if you want a "truly random" number and you're on linux, call srand() once with a number read from /dev/rand or /dev/urand. These files provide about as close to a truly random number as you can get. Your sequence will still be predictable *if* you know the seed, but with a truly random seed, your numbers are also less predictable (i.e. "more" random).

If you're wondering why you can't just read from /dev/rand or /dev/urand all the time when you need a random number, technically you *can,* you just *shouldn't,* since it depletes the random-ness of the numbers in the file, and can affect other programs running on the machine that need random numbers, like ssh.

Share on other sites
Also, if you want a "truly random" number and you're on linux, call srand() once with a number read from /dev/rand or /dev/urand. These files provide about as close to a truly random number as you can get. Your sequence will still be predictable *if* you know the seed, but with a truly random seed, your numbers are also less predictable (i.e. "more" random).

There are a couple of things that are not right in that. First, the devices are /dev/random and /dev/urandom. Second, depending on the rand() implementation, it might be easy to recover the seed after observing a relatively short sequence of generated numbers. So you should keep incorporating entropy into the sequence every so often. /dev/random will block if you try to read from it and the pool of entropy is depleted, while /dev/urandom will always return a number without blocking, and a high-quality PRNG will be used if there is no more entropy. I believe /dev/urandom is random enough for every purpose I can think of.

Share on other sites
Using rand() is perfectly fine *if* you only need a uniform distribution. There are a lot of times where this isn't the case (for example, generating white noise, where you want a gaussian distribution). In those cases you'll need some kind of random number generator. I'd recommend the boost::random library, which lets you specify any distribution you want.

Not true. The default LCG included in most rand() implementations does not produce a uniform distribution. Look up "random numbers fall mainly in the planes" from G. Marsaglia. Mersenne Twister does a much better job, though, so if you can use that easily without changing much code, I'd definitely recommend it. It's just that usually, this is good enough for most applications which don't require a perfectly uniform distribution, even a rough approximation usually suffices.

Also you can derive any statistical distribution from a uniform distribution - or any other distribution, for that matter - via inverse transform sampling (essentially, invert the cumulative distribution function). For an example with a normal distribution, check out the Box-Muller transform, or the Ziggurat algorithm.

Also, if you want a "truly random" number and you're on linux, call srand() once with a number read from /dev/rand or /dev/urand. These files provide about as close to a truly random number as you can get. Your sequence will still be predictable *if* you know the seed, but with a truly random seed, your numbers are also less predictable (i.e. "more" random).

Again, no. Even if your seed is highly unpredictable, the default LCG will not produce a proper uniform sequence. In fact, it doesn't even matter what your seed is, since a good LCG is a proper permutation - you'll just be starting at a different place in the cycle. A similar argument holds for Mersenne Twister, though it's not a permutation iirc. At least in the context of a game, if you're talking cryptography it's obviously different.

If you're wondering why you can't just read from /dev/rand or /dev/urand all the time when you need a random number, technically you *can,* you just *shouldn't,* since it depletes the random-ness of the numbers in the file, and can affect other programs running on the machine that need random numbers, like ssh.

This really depends how much entropy you need. There are methods to stretch a single 128-bit value into an effectively infinite bitstream which is computationally indistinguishable from a truly uniformly random bitstream, but this is really going off-topic and overkill in this context. I don't wanna be "that guy" SOTL was talking about

Edited by Bacterius

Share on other sites
In response to Bacterius's post I want to say that the rand() implementation you get in Linux (i.e., GLIBC's implementation) these days is much much better than a simple LCG.

Share on other sites
In response to Bacterius's post I want to say that the rand() implementation you get in Linux (i.e., GLIBC's implementation) these days is much much better than a simple LCG.

That's good to know. Better be safe than sorry though. I liked the C++11 way of having multiple standard PRNG's with a common interface so you could choose which one you wanted (I think there was the LCG, a MT, a couple lagged generators and a few other simple ones) and could easily change with a simple token replace.

Share on other sites

EDIT: Never mind, this is in general programming.  Carry on.

Edited by BeerNutts

Share on other sites

In general, using rand() is perfectly fine for basically everything unless you're running a gambling site, ultra high precision probabilistic algorithm, cryptographic infrastructure, or other highly specialized tasks. Nothing like information overload to put somebody off programming.

Using rand() is perfectly fine *if* you only need....

I completely agree that rand() is less-than perfect in many many situations. If the rand() implementation varies from compiler to compiler (which I think was the case was the C++98 standard, but I might be mistaken here), then that's yet another reason why you'll need your own implementation, so (for example) generated map seeds can be shared over the internet with users using your game compiled with different compilers on different operating systems.

My only point (directed at the OP's 'why such a simple response'), was that rand() works perfectly fine for a console game or a tetris/asteroids clone, and that anyone not understanding when and why to call srand() more than once, is also not needing anything better than rand(), and probably wouldn't understand how something like a Mersenne Twister implementation works.

Thankfully, C++11 has new better psuedo-random number generators (such as built-in standardized mersenne twister, among others), though because their usage is all templatey and classy, which is great for intermediate and advanced C++ users, a beginner will probably still use rand().

Discussion among more experienced developers (like in this thread) about the nitpicky implementation details is of immense value and very educational to people who didn't go through college (like myself). It just overwhelms people still trying to understand the difference between references and pointers, and possibly drives them away from programming because "it's too confusing".

Edited by Servant of the Lord

Share on other sites

One thing I didn't see anybody here mention (unless I skipped something) is that calling srand with the same value to get the same sequence is not portable. Sure, if you run it on the same implementation, you'll get the same sequence, but the algorithm used by rand is completely implementation defined, and switching to a different implementation of the standard library is bound to give you a different sequence.

Calling srand more than once is theoretically fine but you need to be aware of how it works. It's very unlikely you'll have any serious reasons to do it, and if it's to get the same sequence as in the above case, you probably want to use either your own RNG or a RNG library which guarantees the algorithm will stay the same always.

EDIT: just realized a part of the post above says this =/ But yes, that pretty much renders calling srand again mostly useless.

Edited by Sik_the_hedgehog