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

Started by
24 comments, last by Cornstalks 11 years, 4 months ago
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.
Advertisement

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.

The purpose of rand() is to get a random (well, seemingly random) value.

srand() sets the starting point for the repeatable series of random values. Each time you call srand(), if you feed it the same seed, it will reset the series, and instead of getting seemingly random values, you get the same series you got last time i.e. not random anymore.

Since most new users want random values, if they call it twice or more during the course of their program, they are probably doing it accidentally, not understanding what it does, and not understanding that it makes their values less random.

It's not at all bad to call srand() multiple times. It's not at all bad to use srand() to intentionally get the same repeatable series of numbers. But if that's not what a new programmer is wanting or expecting, then they come asking why it's not random. The easiest explanation is, if you want it random, seed it with time() and only once at startup.

If it's not seeded with time() (which returns the number of seconds since January 1st, 1970), I think it defaults to a seed of 0, which means each time the user starts the program, they get the same series of "random" numbers, and think rand() is broken.

  • "How come each time I run my game, the random numbers are the same series/pattern?!" -> You didn't seed it, or else seeded it with the same value each time the program runs.
  • "How come each time I run my game, every number is completely identical, even in the same execution?!" -> You call srand() before each usage of rand(), and reset the sequence, and you seeded it with an unchanging value.
  • "How when I call rand() multiple times in a row, the numbers are identical, but in other places in my code, a different group of rand() calls has a different identical number?" -> You call srand(time()) before each call to rand(), but a full second hasn't passed between each call to ssrand() in that particular block of code (so you are resetting the sequence, and in the consecutive calls to srand(), time() is feeding it the same value since a full second hasn't passed and time() returns the number of seconds since Jan 1st, 1970).

It's perfectly fine to call srand() more than once. Not in the least harmful. But new programmers who don't understand what srand() does, and didn't read the documentation, they are using srand() incorrectly, and almost always (>99%) are only really wanting it to be seeded with time() and called once at startup. They can learn the rule first "Don't call srand() more than once, and only call it with time()", and learn the exception to the rule later, "unless you intentionally want to repeat the same sequence of numbers, which is useful for things like procedural generation". Their main focus at their current level of code should be understanding code-flow, not the scientific theory of random number generators.

It's a perfectly reasonable and helpful answer, though I like to give the exception with the rule, "Don't call srand() more than once, and only call it with time(), unless you intentionally want to repeat the same sequence of numbers, which is useful for things like procedural generation".

A perfectly unreasonable and stupid answer is the people who reply to a 12 year old programming newbie with, "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. It'll waste the next week of your life, and you won't understand it anyway (since you are still learning the basics of programming), but at least you'll think I am some awesome l33t c0d1ng haxor." rolleyes.gif

Good answer, apart from you kind of went off on one in the last paragraph ;)
"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

I did, didn't I? laugh.png

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. dry.png

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

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

It does sound suspiciously familiar... unsure.png sleep.png

[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 sad.png 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.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

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.

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.
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 mellow.png

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

This topic is closed to new replies.

Advertisement