Random numbers are an important topic in computer science, especially with respect to game programming. Without them, games would always make the same move every time you played them. Needless to say, it would be no fun if they always reacted in the exact same way each time you played them. Imagine a simple game like poker where the computer always dealt the same hand every game. After playing the first game, you would have figured out what cards the computer had and you would never lose (or have any fun!)
Generating Random Numbers in C
#include <stdio.h> /* printf */
#include <stdlib.h> /* rand */
int main(void)
{
int i;
for (i = 0; i < 10; i++)
printf("%i\n", rand());
return 0;
}
Output:
Microsoft
(Windows)Borland
(Windows)gcc/clang
(Linux)gcc/clang
(macOS) 41 18467 6334 26500 19169 15724 11478 29358 26962 24464 130 10982 1090 11656 7117 17595 6415 22948 31126 9004 1804289383 846930886 1681692777 1714636915 1957747793 424238335 719885386 1649760492 596516649 1189641421 16807 282475249 1622650073 984943658 1144108930 470211272 101027544 1457850878 1458777923 2007237709
Constraining and Seeding the Pseudo-Random Number Generator
Usually, we want to generate random numbers within a specific range, rather than between 0 and 32,767 (or 2,147,483,647). The modulus operator, %, is very handy for this. This example generates 10 numbers between 1 and 10:
#include <stdio.h> /* printf */
#include <stdlib.h> /* rand */
int main(void)
{
int i;
for (i = 0; i < 10; i++)
printf("%i\n", rand() % 10 + 1);
return 0;
}
Output:
Microsoft Borland GNU gcc 2 8 5 1 10 5 9 9 3 5 1 3 1 7 8 6 6 9 7 5 4 7 8 6 4 6 7 3 10 2
Notice that some numbers are duplicated. This is normal and is what random means.
If I run the program 5 times, this is the output of the 5 runs: (each column is a run). See a problem?
Issues with the pseudo-random number generator:2 2 2 2 2 8 8 8 8 8 5 5 5 5 5 1 1 1 1 1 10 10 10 10 10 5 5 5 5 5 9 9 9 9 9 9 9 9 9 9 3 3 3 3 3 5 5 5 5 5
void srand(int seed);
|
gcc on Linux:
srand(1): 1804289383 846930886 1681692777 1714636915 1957747793 srand(2): 1505335290 1738766719 190686788 260874575 747983061 srand(3): 1205554746 483147985 844158168 953350440 612121425 srand(3): 1205554746 483147985 844158168 953350440 612121425 srand(2): 1505335290 1738766719 190686788 260874575 747983061 |
Of course, this leads to the same problem: how do we randomly choose the position in the list? The computer doesn't really do anything randomly. So we improvise:
#include <stdio.h> /* printf */
#include <stdlib.h> /* rand, srand */
#include <time.h> /* time */
int main(void)
{
int i;
srand(time(NULL));
for (i = 0; i < 10; i++)
printf("%i ", rand());
return 0;
}
Running the program 5 times gives these outputs: (compiled with gcc on Linux)
A note about the time function:1384334524 735471424 1860098722 694496962 1657646138 301995943 1803857288 1201859531 1067245105 2108720089 2135987043 1232099519 337709210 1659609624 271785989 709050360 181970958 1810020192 440129707 1154963843 1470269329 835711329 522547729 1580784891 2040547807 449856168 73845202 562074047 1973143356 89221058 804551614 439323139 707386248 1501960159 1661825977 190661976 2113203095 1461611550 1358673356 1170961921 954882118 1397642217 1261901805 1265485962 525660488 1560563048 1788825829 2012740412 1662747006 121217212
This was run on Linux 3 times very quickly:
1752971591 885825227 1897503914 506494125 570682061 812192660 684485179 1706390114 1643637072 1332816372 1752971591 885825227 1897503914 506494125 570682061 812192660 684485179 1706390114 1643637072 1332816372 1752971591 885825227 1897503914 506494125 570682061 812192660 684485179 1706390114 1643637072 1332816372
Note: Generally speaking, if you truly want a pseudo-random sequence, you should only seed the random number generator once at the beginning of the program (e.g. the first line in main), and never seed it again. If you seed it multiple times, you are actually biasing the sequence, causing the distribution of numbers to be less random.
Putting a "Wrapper" Function Around rand()
Although using the modulo operator, %, is simple and effective, it can be tedious and error-prone to use it to constrain the random numbers. A better solution is to write your own function that does all of the work for you.This simple function takes two parameters which specify a range (inclusive) that the random number should be within: (Plug in some numbers for low and high to convince yourself that the formula does work.)
Examples:int RandomInt(int low, int high) { int number = rand() % (high - low + 1) + low; return number; }
Sample program:Random(10, 20) ---> rand() % (20 - 10 + 1) + 10 ---> rand() % 11 + 10 ---> (0 to 10) + 10 ---> 10 to 20 Random(1, 100) ---> rand() % (100 - 1 + 1) + 1 ---> rand() % 100 + 1 ---> (0 to 99) + 1 ---> 1 to 100 Random(-5, 5) ---> rand() % (5 - -5 + 1) + -5 ---> rand() % 11 + -5 ---> (0 to 10) + -5 ---> -5 to 5 Random(1, 2) ---> rand() % (2 - 1 + 1) + 1 ---> rand() % 2 + 1 ---> (0 to 1) + 1 ---> 1 to 2 Random(-15, -5) ---> rand() % (-5 - -15 + 1) + -15 ---> rand() % 11 + -15 ---> (0 to 10) + -15 ---> -15 to -5
|
Output from running the program 5 times:
19 14 17 15 11 19 11 19 13 14 138 140 140 106 134 115 118 182 155 101 6 -9 -7 -7 -9 6 5 7 5 2 12 16 16 14 11 14 16 13 14 18 152 148 165 176 180 130 121 119 187 193 -6 -7 -2 -6 2 4 -4 7 1 6 12 14 10 16 13 12 17 13 19 12 157 143 199 159 132 193 163 136 131 178 9 -2 -2 10 -5 -9 5 -7 2 -2 12 14 10 16 13 12 17 13 19 12 157 143 199 159 132 193 163 136 131 178 9 -2 -2 10 -5 -9 5 -7 2 -2 20 14 18 18 10 19 15 19 20 17 169 128 197 118 144 172 189 129 190 168 -9 -8 -10 10 -2 6 2 4 6 -4 |
Notice that the 3rd and 4th runs are the same. This is because the 4th run was run immediately after the 3rd run and the time hadn't changed.
Interactive example:
|
Output from running the program 4 times:
Enter lowest value: 10 Enter highest value: 20 How many numbers? 10 18 11 19 12 20 17 13 19 20 20 |
Here is an example of a simple pseudo-random number generator:
Notes: