Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: seeding random number generator outside of main()

Tags:

c++

random

I was creating a simple program that simulates a coin toss for my class. (Actually, class is over this term and i'm just working through the rest of the projects that weren't required). It involves the creating and calling a function that generates a random number between 1 and 2. Originally, I tried to seed the random number generator within the function that would be using it (coinToss); however, it did not produce a random number. Each time the program was run it was the same number as though I had only used

rand()

instead of

unsigned seed = time(0);
srand(seed);
rand();

Yet, when i moved the above within

int main()

it worked fine.

My question is 1)why did it not work when setup within the function that called it and (2) how does rand() have access to what was done by srand() if they do not both occur in the same function? Obviously, i'm a beginner so please forgive me if i didn't formulate the question correctly. Also, my book has only briefly touched on rand() and srand() so that's all i really know.
thanks for any help!

Pertinent code:

First attempt that didn't work:

int main()
{  
    //...........
    coinToss();
    //...........
 }

 int coinToss()
 {
    unsigned seed = time(0);
    srand(seed);

    return 1 + rand() % 2;
  }

Second attempt which did work:

int main()
{
    unsigned seed = time(0);
    srand(seed);

    coinToss();
 }

 int coinToss()
 { 
    return 1 + rand() % 2;
  }
like image 371
knobcreekman Avatar asked Dec 15 '10 21:12

knobcreekman


3 Answers

You probably only want to seed the random number generator once. rand() returns the next pseudo-random number from it's internal generator. Every time you call rand() you will get the next number from the internal generator.

srand() however sets the initial conditions of the random number generator. You can think of it as setting the 'starting-out point' for the internal random number generator (in reality it's a lot more complicated than that, but it's a useful cognitive model to follow).

So, you should be calling srand(time(0)) exactly once in your application - somewhere near the beginning. After that, you can call rand() as many times as you want!

However

To answer your actual question - the first version doesn't work because time() returns the number of seconds since the epoch. So If you call coinToss() several times in a second (say, if you wanted to simulate 100 coin tosses), then you'd be constantly seeding the random number generator with the same number, thereby resetting it's internal state (and thus the next number you get) every time.

Anyway - using time() as a seed to srand() is somewhat crappy for this very reason - time() doesn't chage very often, and worse, it's predictable. If you know the current time, you can work out what rand() will return. The internet has many, many examples of better srand() seeds.

like image 80
Thomi Avatar answered Oct 05 '22 23:10

Thomi


Pseudo-random number generators (like rand) work by taking a single starting number (the seed) and performing a numeric transformation on it each time you request a new number. You want to seed the generator just once, or it will continually get reset, which is not what you want.

As you discovered, you should just call srand just once in main. Also note that a number of rand implementations have pretty short cycles on the low 4 bits or so. In practice this means you might get an easily predictable repeating cycle of numbers You might want to shift the return from rand right by 4-8 bits before you take the % 2.

EDIT: The call would look something like: return 1 + (rand() >> 6) % 2;

like image 35
Mark B Avatar answered Oct 05 '22 23:10

Mark B


Seed only once per program, not every time you call coinToss()

like image 27
John Dibling Avatar answered Oct 05 '22 23:10

John Dibling