CIS 22 - Simulations: Random Num
C/C++ Random Number Generation | Distributions
To generate random numbers in C/C++, you need to use rand() (Don’t forget to include the <stdlib.h> (for C) <cstdlib> (for C++) at the top of your program). What this basically does is return a random integer from 0 to RAND_MAX (a macro defined in the library). Here’s a simple program that outputs what RAND_MAX is, as well as 10 random integers:
Click to download an executable that illustrates rand() (Run a few times....Notice anything strange?)
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
int randomNumber = 0;
int i = 0;
cout << "Maximum random # = " << RAND_MAX << endl;
for (i = 1;i <= 10;i++)
{
randomNumber = rand();
cout << "Random integer = " << randomNumber << endl;
}
system ("PAUSE");
return 0;
}
At first glance, after executing the code, RAND_MAX is 32767, and you get 10 random numbers. Great, right? Not quite. Run the code a few times, and you should notice something peculiar. See it? The “random” numbers are exactly the same after each run. Why is this? To find out, let me introduce something called the “seed value”. The way C++ works with random numbers (from now on, I’ll refer to them as “pseudo-random”) is that it starts with a number (a seed value: srand (SEED VALUE)), and does some complex arithmetic on it to yield the answer. If the seed value is always the same, your results will always be the same. Here’s a variation on the above code, with a changing seed value.
SAME SEED VERSION:
Click to download an executable that has same seed value
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
int randomNumber = 0;
int i = 0;
cout << "Maximum random # = " << RAND_MAX << endl;
for (i = 1;i <= 10;i++)
{
srand (5);
randomNumber = rand();
cout << "Random integer = " << randomNumber << endl;
}
system ("PAUSE");
return 0;
}
CHANGING SEED VERSION:
Click to download an executable that has a changing seed value
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
int randomNumber = 0;
int i = 0;
cout << "Maximum random # = " << RAND_MAX << endl;
for (i = 1;i <= 10;i++)
{
srand (i);
randomNumber = rand();
cout << "Random integer = " << randomNumber << endl;
}
system ("PAUSE");
return 0;
}
At least we got some different results than last time. Now change the macro value to a different number, compile, and then execute again. Notice that we are getting different results every time. But there’s a problem. If we have to change the seed value to get pseudo-random numbers, and the computer has to know at compile-time what that value is, how can we get different results in our programs? The answer is to pick a value that is ever-changing. In most cases, the system timer fits the bill. Include the <time.h> (for C) <ctime> (for C++) library and change your “seed value” line to read:
srand (time(0));
This tells the compiler that you’ll be getting the seed value from the system timer. Now run your program multiple times, and you’ll see a big difference in the results. If you do runs that are close in time, you can see a pattern in the output.
This is great if you want a bunch of random numbers to print, but what if you want a bunch of numbers in a specific range? What if I want 10 random numbers from 1 to 10? The answer is to use the modulus operator ‘%’ on your random number. Using the modulus operator alone will give you a number from 0 to the number on the right of the % - 1. So if I want 1-10, I can’t simply put:
randomNumber = rand() % 10;
This will yield numbers between 0 and 9, not what I want. To remedy this, simply add 1 at the end (in the order of operations, the ‘%’ will be evaluated before the ‘+’). So your line should read:
randomNumber = rand() % 10 + 1;
TIME SEED VERSION:
Click to download an executable that has system timer as the seed value (Run a few times)
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
int randomNumber = 0;
int i = 0;
srand (time(0));
cout << "Maximum random # = " << RAND_MAX << endl;
for (i = 1;i <= 10;i++)
{
randomNumber = rand();
cout << "Random integer = " <<
randomNumber << endl;
}
system("PAUSE");
return 0;
}
Most people think that a random number is just a random number. Most seem to think in terms of uniform distribution. That is when in a given range of random numbers, every number is equally likely. In actuality, there are many distributions. Why are there different types of distribution? The answer is that in many situations, every number is not equally likely, but fall into certain patterns. Just look at how water current at once seems to be random, but has a definite pattern. In general the numerous distributions can be very complicated and technical, but for us, I'll concentrate on 2 distributions. These are normal and uniform. The great thing about modular programming is that you can have a function/method that only has the job of generating a random number, without the rest of your program knowing how it's being calculated. So adapting your simulation to different distributions only requires you to change the implementation of your random function/method. The distributions tend to be differentiated by complex formulas that a randomly generated number goes through. The links below explain how to implement your random function/method to follow the desired distribution.
In general, uniform distribution is achieved by setting the seed to the system timer and generating/returning the number, without any complex formulas to be concerned with:
int randomNumberGenerator (int max)
{
srand (time (0)); /* How you set the seed value to the system timer */
/* Return an integer from 1 - max because of the explicit integer cast (from double) */
return (int) (rand() % max + 1);
}
It's that simple!!! This will work for any uniform distribution. As you see, every number is equally likely to return from this function/method. If you wanted a value from 0 - max, all you would have to do is add 1 to the max at the beginning of the function/method, and remove the "+ 1" from the line that calls rand(). Aside from that, this will work wonderfully if uniform distribution is what you're looking for.
Here's an applet I made that demonstrates uniform distribution. As you repeatedly click the "Roll" button, you'll see that every value is equally likely, and that some of the occurrences may be much higher values.:
SECTION UNDER CONSTRUCTION
Back to CIS 22 home page