Introduction to Random Number Generation

By: Johnson Laguerre

Quick–choose a number between 1 and 10! What number did you choose?

Let’s say you chose the number 4.

#include <stdio.h>

int main(void)
{
    int num = 0;

    printf("Choose a number between 1 and 10: ");

    do
    {
      scanf("%d", &num);
    } while (num < 1 || num > 10);

    printf("You chose: %d.\n", num);

    return 0;
}

If we ran our code, we would see this:

Choose a number between 1 and 10: 4
You chose: 4.

Here, we take user input and store the value 4. However, let’s say we were debugging our code and didn’t want to keep entering random numbers by hand. Is there anything we could do to save ourselves the effort?


To the rescue: rand() and srand().

Thankfully, C supplies us with two functions in stdlib.h to help us generate random numbers: rand() and srand().

First, we’ll look at rand(). It can be used to return a random integer between 0 and RAND_MAX, a constant that will be at least 32767. You can assign a variable its return value like so:

#include <stdio.h>
#include <stdlib.h> // Don't forget to include this!

int main(void)
{
    // num1 is assigned a value between 0 and RAND_MAX.
    int num1 = rand();

    printf("num1 = %d.\n", num1);

    return 0;
}
num1 = 41.

Pretty neat, huh?

If you want to find out what RAND_MAX is on your system, you can use the following code:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    printf("On my system, RAND_MAX is %d.\n", RAND_MAX);

    return 0;
}
On my system, RAND_MAX is 32767.

Returning a random number between 1 and 10.

Let’s go back to our opening example.

Remember that we can use the modulus operator, %, to return a number between 0 and n-1, where n is the number we modulo by. Let’s perform rand() modulo 10 to return a number between 0 and 9.

// This modulo operation returns a number between 0 and 9.
int random_num = rand() % 10;

Now, we can add 1 to the result to bring the value to between 1 and 10.

// random_num is now between 1 and 10.
random_num += 1;

As a whole, the concept looks like this:

// Generates a random number between 1 and 10.
int random_num = (rand() % 10) + 1;

Returning a random number between any two numbers.

Let’s take this concept a step further. Say you want to return a number between any two numbers. If we use the example above as a guide, we see that our upper bound was 10 and our lower bound was 1, giving us a range of 10 numbers. We can calculate that using this formula:

int range = (upper_bound - lower_bound) + 1;

If we plug 10 and 1 into their proper places, we see that range evaluates to 10.

int range = (10 - 1) + 1;

Now we use what we know to find a different range. I’ve been feeling pretty lucky today, so I want my lower bound to be 7. Maybe you’ve been feeling 100 percent on top of things lately, so we’ll make our upper bound 100.

int lower_bound = 7;
int upper_bound = 100;

Using the formula above, we see that range evaluates to 94.

int range = (100 - 7) + 1;

Next, we modulo rand() by range to get numbers between 0 and 93.

int another_random_num = rand() % range;

Finally, we add lower_bound to the previous result to have our numbers fall between 7 and 100.

another_random_num += lower_bound;

If we hard-coded all of the values and put the expression on one line, it would look like this:

// (rand() % (upper_bound - lower_bound + 1)) + lower_bound
int another_random_num = (rand() % (100 - 7 + 1)) + 7

rand() and srand(): psuedo-random generators.

I have a secret to tell you: the result of rand() actually isn’t entirely random. Officially, rand() and srand() are known as “pseudo-random sequence generation functions” . Simply put, that means the output from rand() can be predicted if you know its input and underlying algorithm. However, we don’t see it taking any input, so where is the input coming from?

Behind the scenes, it is given a positive integer, or unsigned int, called a seed to operate on. When you start your program, the seed has a default value of 1. If you use that seed across different program runs, you will generate the same set of random numbers each time.


Seeding rand(): the srand() function.

This is where srand() comes into play. Once you pass srand() a seed, rand() can use it to generate random numbers.

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    // Declaring and initializing a seed variable.
    int your_seed = 4; 

    // Passing your_seed to srand().
    srand(your_seed);

    // Calling rand() after seeding srand().
    int last_random_num = rand();

    printf("Your random number: %d.\n", last_random_num);

    return 0;
}

Running our code gives us this:

Your random number: 0.

The inner workings of rand() and srand().

That’s great, but as it currently stands, a little mysterious. How exactly do the two work together? Well, if we were to peek inside of stdlib.h, we would see code that looked like this:

// In stdlib.h.

// seed is visible to both rand() and srand(). Its default value is 1.
unsigned int seed = 1;

// Note: This is not the actual algorithm, only a simplified example.
int rand(void)
{
    seed = (seed * 5) + 1;
    return (seed / 2) % 10;
}

void srand(unsigned int your_seed)
{
    // Sets the global seed variable to the your_seed value passed into the function.
    seed = your_seed;
}

When we ran our example from earlier in the section, the process to get our 0 value worked like this.

// In the background...

// seed starts as 1.
unsigned int seed = 1;

void srand(unsigned int your_seed)
{
    // Reassigns seed using your_seed.
    seed = 4;
}

int rand(void)
{
    // seed evaluates to 21, which is then stored in the global variable.
    seed = (4 * 5) + 1;

    // Returns 0 to the main function.
    return (21 / 2) % 10;
}

It is considered good practice to call srand() only once, at the start of your program. While useful for predictability, you may not want to use the same seed every time. In that case, pass time(NULL) to srand() to use the current time as a seed–and don’t forget to include <time.h>!

#include <stdio.h>
#include <stdlib.h> // rand() and srand().
#include <time.h> // Accessing the time() function.

int main(void)
{
    // Seeding srand() with the current time.
    srand(time(NULL));

    // Calling rand() after seeding srand().
    int last_random_num = rand();

    printf("Your random number: %d.\n", last_random_num);

    return 0;
}