First random number is not random

Started by
7 comments, last by Conner McCloud 18 years, 10 months ago
I have the following very simple piece of code:

#include <iostream>
#include <ctime>

namespace
{
	bool g_seeded = false;
}

int RandomInt(const int min, const int max)
{	
	if(!g_seeded)
	{
		srand(time(0));
		g_seeded = true;
	}

	return min + int((max - min + 1) * rand() / (RAND_MAX + 1.0));
}

int main()
{
	std::cout << RandomInt(0, 7) << "\n";

	return 0;
}

It's been only printing 7 for me, and I don't see why. If I call RandomInt() more than once, then the values are random, but for the first time it's always the same. Does anyone know why that would be? [sad]
Advertisement
Quote:Original post by Hylo
Looks like the first time through you dont seed the random number generator..


Andrew


Actually, he's doing that part fine.

The problem is in how you implemented RandomInt()... Try changing it to:

return min + rand()%(max-min+1);

...

The reason your version didn't work is a little hard to explain. Let me just tell you this... rand() returns a number from 0 to 32,767 if I remember correctly. Now the thing is, every second, the 1st number returned by rand increases by 1 (this is because you are seeding based on time(NULL) which is in *seconds*).

So, run your program the 1st time, maybe the 1st number returned is 9,124. Then wait 5 seconds, run it again, now it returns 9,129... And so on... Because of the way you set up your math though, 9,124 and 9,129 map to the same number. That's why it's better to use the modulus (%) operator.

Hope that makes sense :)

roos
Quote:Original post by Hylo
Looks like the first time through you reseed the generator with the same numer


Andrew


Nope. It's a different value everytime provided the next time you run the program it has been over about a second later.

EDIT:
Quote:Original post by roos
Quote:Original post by Hylo
Looks like the first time through you dont seed the random number generator..


Andrew


Actually, he's doing that part fine.

The problem is in how you implemented RandomInt()... Try changing it to:

return min + rand()%(max-min+1);

...

The reason your version didn't work is a little hard to explain. Let me just tell you this... rand() returns a number from 0 to 32,767 if I remember correctly. Now the thing is, every second, the 1st number returned by rand increases by 1 (this is because you are seeding based on time(NULL) which is in *seconds*).

So, run your program the 1st time, maybe the 1st number returned is 9,124. Then wait 5 seconds, run it again, now it returns 9,129... And so on... Because of the way you set up your math though, 9,124 and 9,129 map to the same number. That's why it's better to use the modulus (%) operator.

Hope that makes sense :)

roos


Ah, that does indeed make sense [smile]. CANDY FOR YOU. Come to think of it, the program started printing 0 10 minutes later instead of 7.

Now, does: min + rand()%(max-min+1) have good "randomness"? I've heard certain formulas for calculating random numbers have problems because of not taking into account "low bits" or something or other. Is there a "best" way to calculate random numbers like this?
double Random() // returns [0,1) {  static bool seeded(false);   if(!seeded)   {    srand(time(0));    seeded = true;   }    return static_cast<double>(rand())/static_cast<double>(RAND_MAX+1); }template <typename T> T Random(const T &min, const T &max) // returns [min,max) {  return min+static_cast<T>(static_cast<double>(max-min)*Random()); }
Chess is played by three people. Two people play the game; the third provides moral support for the pawns. The object of the game is to kill your opponent by flinging captured pieces at his head. Since the only piece that can be killed is a pawn, the two armies agree to meet in a pawn-infested area (or even a pawn shop) and kill as many pawns as possible in the crossfire. If the game goes on for an hour, one player may legally attempt to gouge out the other player's eyes with his King.
Quote:Original post by smart_idiot
*** Source Snippet Removed ***


Ooh! Templated! Very nice. I think I will use this. [smile]

Well... rand() isn't bad, but it depends on what you are doing. Personally, I've never really run into a situation where rand() didn't do the job.

As far as other RNG algorithms go, I haven't tried any but I have heard of one called Mersenne Twister. It's supposedly pretty good and fast to compute..

roos
++vote for Mersenne Twister.
Chess is played by three people. Two people play the game; the third provides moral support for the pawns. The object of the game is to kill your opponent by flinging captured pieces at his head. Since the only piece that can be killed is a pawn, the two armies agree to meet in a pawn-infested area (or even a pawn shop) and kill as many pawns as possible in the crossfire. If the game goes on for an hour, one player may legally attempt to gouge out the other player's eyes with his King.
Quote:Original post by roos
Well... rand() isn't bad, but it depends on what you are doing. Personally, I've never really run into a situation where rand() didn't do the job.

As far as other RNG algorithms go, I haven't tried any but I have heard of one called Mersenne Twister. It's supposedly pretty good and fast to compute..

roos


Quote:Original post by smart_idiot
++vote for Mersenne Twister.


This "Mersenne Twister" sounds very good; I just wikipediaed it. I'll go see what it does, thanks again roos/smart_idiot.
Quote:Original post by roos
Actually, he's doing that part fine.

The problem is in how you implemented RandomInt()... Try changing it to:

return min + rand()%(max-min+1);

...

The reason your version didn't work is a little hard to explain. Let me just tell you this... rand() returns a number from 0 to 32,767 if I remember correctly. Now the thing is, every second, the 1st number returned by rand increases by 1 (this is because you are seeding based on time(NULL) which is in *seconds*).

So, run your program the 1st time, maybe the 1st number returned is 9,124. Then wait 5 seconds, run it again, now it returns 9,129... And so on... Because of the way you set up your math though, 9,124 and 9,129 map to the same number. That's why it's better to use the modulus (%) operator.

Hope that makes sense :)

roos

Don't use the modulus operator. It is biased towards the low order bits, which are often less random than the high order bits. As you explain, consecutive calls to time(0) have most of their variation in those low order bits, so for that first call [and only for that first call], a modulus might well be a better move. But you only seed once, so in the long run his original implementation was not only fine, but preferable on many systems.

If you are running your program so quickly that you see such problems, just throw away your first value.
if(!g_seeded){    srand(time(0));    rand();    g_seeded = true;}

CM

This topic is closed to new replies.

Advertisement