Jump to content

  • Log In with Google      Sign In   
  • Create Account


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


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
25 replies to this topic

#1 MarkS   Prime Members   -  Reputation: 875

Like
0Likes
Like

Posted 27 December 2012 - 01:43 PM

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"?



Sponsor:

#2 Paradigm Shifter   Crossbones+   -  Reputation: 5151

Like
0Likes
Like

Posted 27 December 2012 - 01:48 PM

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).
"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

#3 SimonForsman   Crossbones+   -  Reputation: 5804

Like
0Likes
Like

Posted 27 December 2012 - 01:49 PM

<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)
I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!

#4 MarkS   Prime Members   -  Reputation: 875

Like
0Likes
Like

Posted 27 December 2012 - 01:50 PM

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.



#5 fastcall22   Crossbones+   -  Reputation: 4013

Like
1Likes
Like

Posted 27 December 2012 - 01:52 PM

It's not necessarily calling srand multiple times, it's beginners repeatedly calling srand with time(0) 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, 27 December 2012 - 01:53 PM.

c3RhdGljIGNoYXIgeW91cl9tb21bMVVMTCA8PCA2NF07CnNwcmludGYoeW91cl9tb20sICJpcyBmYXQiKTs=

#6 Paradigm Shifter   Crossbones+   -  Reputation: 5151

Like
0Likes
Like

Posted 27 December 2012 - 01:54 PM

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, 27 December 2012 - 01:56 PM.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

#7 Álvaro   Crossbones+   -  Reputation: 11942

Like
3Likes
Like

Posted 27 December 2012 - 01:56 PM

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.

#8 Khatharr   Crossbones+   -  Reputation: 2865

Like
0Likes
Like

Posted 27 December 2012 - 02:18 PM

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, 27 December 2012 - 02:18 PM.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

#9 santa01   Members   -  Reputation: 307

Like
1Likes
Like

Posted 27 December 2012 - 02:36 PM

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


#10 Álvaro   Crossbones+   -  Reputation: 11942

Like
0Likes
Like

Posted 27 December 2012 - 02:41 PM

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

#11 jwezorek   Crossbones+   -  Reputation: 1631

Like
2Likes
Like

Posted 27 December 2012 - 02:58 PM

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.

#12 MarkS   Prime Members   -  Reputation: 875

Like
0Likes
Like

Posted 27 December 2012 - 02:59 PM

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.



#13 Servant of the Lord   Crossbones+   -  Reputation: 17257

Like
8Likes
Like

Posted 27 December 2012 - 03:00 PM

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


Edited by Servant of the Lord, 27 December 2012 - 03:24 PM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

[Fly with me on Twitter] [Google+] [My broken website]

All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal


#14 Paradigm Shifter   Crossbones+   -  Reputation: 5151

Like
0Likes
Like

Posted 27 December 2012 - 03:09 PM

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

#15 Servant of the Lord   Crossbones+   -  Reputation: 17257

Like
0Likes
Like

Posted 27 December 2012 - 03:23 PM

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


It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

[Fly with me on Twitter] [Google+] [My broken website]

All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal


#16 MarkS   Prime Members   -  Reputation: 875

Like
0Likes
Like

Posted 27 December 2012 - 03:37 PM

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



#17 Bacterius   Crossbones+   -  Reputation: 8178

Like
0Likes
Like

Posted 27 December 2012 - 05:32 PM

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.

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.


The slowsort algorithm is a perfect illustration of the multiply and surrender paradigm, which is perhaps the single most important paradigm in the development of reluctant algorithms. The basic multiply and surrender strategy consists in replacing the problem at hand by two or more subproblems, each slightly simpler than the original, and continue multiplying subproblems and subsubproblems recursively in this fashion as long as possible. At some point the subproblems will all become so simple that their solution can no longer be postponed, and we will have to surrender. Experience shows that, in most cases, by the time this point is reached the total work will be substantially higher than what could have been wasted by a more direct approach.

 

- Pessimal Algorithms and Simplexity Analysis


#18 magicstix   Members   -  Reputation: 191

Like
0Likes
Like

Posted 27 December 2012 - 05:51 PM

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. 



#19 Álvaro   Crossbones+   -  Reputation: 11942

Like
1Likes
Like

Posted 27 December 2012 - 06:08 PM

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.

#20 Bacterius   Crossbones+   -  Reputation: 8178

Like
0Likes
Like

Posted 27 December 2012 - 06:10 PM

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


Edited by Bacterius, 27 December 2012 - 06:12 PM.

The slowsort algorithm is a perfect illustration of the multiply and surrender paradigm, which is perhaps the single most important paradigm in the development of reluctant algorithms. The basic multiply and surrender strategy consists in replacing the problem at hand by two or more subproblems, each slightly simpler than the original, and continue multiplying subproblems and subsubproblems recursively in this fashion as long as possible. At some point the subproblems will all become so simple that their solution can no longer be postponed, and we will have to surrender. Experience shows that, in most cases, by the time this point is reached the total work will be substantially higher than what could have been wasted by a more direct approach.

 

- Pessimal Algorithms and Simplexity Analysis





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS