Generating random numbers is an important step in many practical applications like science, arts, statistics, cryptography, gaming, and many other fields. Let’s see how we can generate random numbers in C++ using the rand() function.

The rand() function

The rand() is a built-in function of C++ that returns a pseudo-random integral number in the range of 0 to RAND_MAX (which is equal to the maximum value the int data type can hold, i.e., 2147483647).

Let’s write our program and call the rand() function three times and see the output:

Press + to interact
#include<iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
int main()
{
cout << rand() << endl;
cout << rand() << endl;
cout << rand() << endl;
return 0;
}
  • Line 2: #include<cstdlib> is a standard library used for the rand() function.

  • Lines 7–9: We display random numbers on the console by calling the rand() function three times.

Instruction: Run the above program three times and check the output. You should notice a problem. Look at the output carefully.

You must have noticed that there is always the same output when we run the above program:

1804289383
846930886
1681692777

We will discuss in a while why this happens. However, first let’s understand the functionality behind this rand() function.

The working of the rand() function

The rand() function has several types of implementation. One of the implementations (which we will present) works using polynomials. Let’s recall what a polynomial is.


Polynomial

A polynomial is a mathematical function of the following format:

f(x)=a0 + a1x1 + a2x2 + ... + anxnf(x) = a_0 \space + \space a_1x^1 \space + \space a_2x^2 \space + \space ...\space+\space a_nx^n

where xx is the variable on which the function f(x)f(x) is dependent. Let’s take an example of a polynomial with the following:  n=2,a0=3,a1=5,a2=7\space n=2, a_0=3, a_1=5, a_2=7

f(x)=3 + 5x1 + 7x2f(x) = 3 \space + \space 5x^1 \space + \space 7x^2

Evaluation of a polynomial

We can evaluate the polynomial function on a certain value of x=ax=a by putting aa at every place where the variable xx is in the function f(x)f(x). For example, the above function at x=4x = 4 will be as follows:

f(4)=3 + 5(4)1 + 7(4)2f(4) = 3 \space + \space 5(4)^1 \space + \space 7(4)^2

f(4)=135f(4) = 135


The rand() function usually holds a polynomial in the background, usually made up of prime number coefficients.

Let’s take the above polynomial as our sample polynomial and make our own random function. We’ll call it the custom_rand() function.

Press + to interact
int f(int x)
{
int ans = 3 + (5* pow(x,1)) + (7*pow(x,2)); // Polynomial function
return ans;
}
// A global variable s, we call it seed variable with 0 as initial value
int s = 0;
int custom_rand()
{
return s = f(s); // Update the seed variable with return value
}

When we call custom_rand() for the first time, f(0) is called and evaluates to 3 (because 3+5×01+7×02=33+5\times 0^1 + 7 \times 0^2 = 3). Not only that, s will now be holding the value 3 before returning. Now, when we call custom_rand() again, it will call f(3) and s will have the next value as 8181 (because 3+5×31+7×32=813+5\times 3^1 + 7 \times 3^2 = 81). So the next random number is 81 and s holds the value 81, and so on. Every time we call rand_custom(), the chain of numbers will continue.

We call the variable s as the seed. A seed is basically the value at which the custom_rand() function calls for evaluating its polynomial.

In each custom_rand() call, the seed variable will be updated with the last returned value.

Let’s see the implementation in the playground below:

Press + to interact
#include<iostream>
#include<math.h>
using namespace std;
int f(int x)
{
int ans = 3 + (5* pow(x,1)) + (7*pow(x,2)); // Polynomial function
return ans;
}
// A global variable s, we call it seed variable with 0 as initial value
int s = 0;
int custom_rand()
{
return s = f(s); // Update the seed variable with return value
}
int main()
{
cout<<custom_rand()<<endl;
cout<<custom_rand()<<endl;
cout<<custom_rand()<<endl;
cout<<custom_rand()<<endl; // overflow is happening
}

There are two problems with the custom_rand() function.

  1. Notice that the sequence is increasing very fast. Very soon, the generated number exceeds the limit of the integer and causes overflow (this is why you will see the negative large number on the fourth custom_rand() call).

  2. Run the above program three times and note the output. Each run generates the same sequence of the three numbers.

Fixing the overflow problem

Fixing the overflow problem is quite easy; what we can do is some wrapping by taking the modulus with a very large prime number (usually, it is one more than the maximum value you want to have). For example, one solution could be this:

Press + to interact
#include<iostream>
#include<math.h>
using namespace std;
long long f(int x)
{ // the type "int" is replaced by 8 byte long long so that atleast
// overflow can be avoided on the boundary case
long long ans = 3 + (5* pow(x,1)) + (7*pow(x,2)); // Polynomial function
return ans;
}
int s = 0;
int custom_rand()
{
return s = f(s) % 100019; // Wrapping by taking modulus % from 100019.
}
int main()
{
cout<<custom_rand()<<endl;
cout<<custom_rand()<<endl;
cout<<custom_rand()<<endl;
cout<<custom_rand()<<endl;
cout<<custom_rand()<<endl;
return 0;
}

Fixing the repeated pattern

Whenever we execute the program again, the seed variable s has the value 0. Therefore, the chain of random numbers will be exactly the same.

How can we solve this problem? Think for a while.

Instruction: Can we somehow change the value of the seed s every time the program starts?

Every time we start the program, we preferably want to initialize s with a random number. However, aren’t we stuck in a loop then? To generate a random number, we need another random number?

The srand(int seed) function

In C++, we can have access to the seed s, that global variable, by the use of the srand(int) function, which takes an integer value as a parameter and assigns the value to the seed s.

As we are making our own random function, let’s, for the sake of avoiding conflict, make the function custom_srand(int). Our implementation will be as follows:

Press + to interact
...
int f(int x)
.
.
.
// A global variable s, we call it seed variable with 0 as initial value
int s = 0;
void custom_srand(int seed)
{
s = seed; // Update the seed s with the new value
}
int custom_rand()
.
.
.
int main()
{
custom_srand(5);
cout<<custom_rand()<<endl;
.
.
}

Let’s write some code and see the output:

Press + to interact
#include<iostream>
#include<math.h>
using namespace std;
long long f(int x)
{
long long ans= 3 + (5* pow(x,1)) + (7*pow(x,2)); // Polynomial function
return ans;
}
// A global variable s, we call it seed variable with 0 as initial value
int s = 0;
void custom_srand(int seed)
{
s = seed; // Update the seed s with the new value
}
int custom_rand()
{
return s = f(s)%100019; // Update the seed variable with return value
}
int main()
{
int seed;
cin >> seed; // Enter some value e.g. 0 1 2 1 2
custom_srand( seed ) ;
cout<<custom_rand()<<" "<<custom_rand()<<" "<<custom_rand()<<endl;
}

Enter the input below

Task: Execute the above program at least five times with the following values of the seed as input. Write the output of the program on paper and observe:

Input Seed: 0
Input Seed: 1
Input Seed: 2
Input Seed: 1
Input Seed: 2

Can you see a problem?

Question: Why is this type of input-driven seed problematic?

Let’s say we wrote code for a game in which dice are used. The game could be Ludo or Snakes and Ladders. What if one team already knows on which seed they will yield a maximum number of sixes? They will definitely choose that seed and easily win every time, resulting in cheating.

How can we avoid this control of sequence generation by the end user?


The time(0) function

The C/C++ library has a time() function (which you can think of as int time(0)) that returns the time in seconds passed since the Epoch (00:00:00 UTC, January 1, 1970).

After every second, this value gets incremented by 1; this value is usually hardcoded in every computing machine.

Let’s see how we can use the time(0) function in the following playground.

Press + to interact
#include <iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
int main() {
cout << "Seconds Passed since Jan 01 1970 UTC: "<<time(0)<<endl;
return 0;
}

Task: Execute the above playground multiple times and note the last three digits of the seconds. You should see the seconds changing.

We can use the time(0) function in various applications while writing programs. For example, we can use it to check the execution time from the start of a program till the end of the program.

For example,

  • If we want to check the execution time from the start of the program till the end of the program? Think about using the time(0) function.

  • How can we add the delay in a program?

Application 1: Making the Sleep() function

Let’s use time(0) to make the wait_sec() function. This function is also available in standard C++ with the name Sleep(), defined in the library unistd.h.

  • This function will take an integer sec, which we’ll use to create a pause of that many seconds.

  • We will store the present time in start_Time using the time(0) function.

  • Then time(0) - start_Time will calculate how much time has passed since the execution of the function started.

  • If time(0) - start_Time < sec, we can put the execution in a spin loop; therefore, the loop will break only once sec seconds are consumed.

Let’s see the implementation in the following playground:

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
void wait_sec(int sec);
int main()
{
    int sec=0;

    cout << "After how many seconds you want to terminate the program : " ;
    cin >> sec ;

    cout << "Program starts ...!! " << "\n" ;
    wait_sec( sec ) ;
    cout << "Program terminated ...!! " << "\n";

    return 0;
}

void wait_sec(int sec)
{
	int Start_Time=time(0);
	while( (time(0) - Start_Time) < sec )
    {
    }
}
The wait_sec() function

Instruction: Run the above program for inputs 2, 3, and 4 and note the delay time.

You can also use the wait_sec() function to add the delay in any application or program.

Application 2: Measuring the time of execution in seconds

Now, if we want to check the execution time of the specific program in a number of seconds, we have the following.

  • Idea: We will call the time(0) function at the start and end of the program. While calling these functions, we will also store these two times in int variables. In the end, we will simply subtract the end time from the start time to get the execution time.
Press + to interact
#include <iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
int main() {
int start_time = time(0); // Store the start time
for(int i=1; i < 2000000000; i++); // Add the delay
int end_time = time(0); // Store the end time
cout<<"Execution Time: "<<end_time - start_time<<" seconds"<<endl;
}

Line 7 in the code above adds delay. Note that the for loop does not have a body, but it’s still valid. There is an empty statement (;) following the for loop statement block, so no action is performed within the loop. As a result, the loop simply runs and takes up processing time, causing a delay in the program execution. The for loop is executed, and it adds delay by incrementing i till i is equal to 1999999999.

Let’s now discuss how time(0) can help us generate random numbers.


What will srand(time(0)) do?

Time changes every second, hence the time(0) value changes every second. Can we use this point to our advantage?

Question: What will happen if we write srand(time(0)) in the first line of int main() or anywhere else in the code?

It will initialize the seed with the current time value, which will always differ when we start our program. This way, we will never get the same sequence at every execution time because the time function will not give us the same time as the seed, resulting in a different generated sequence.

For using time(0), we have to add a prototype #include<ctime> or #include<time.h> at the start of the code.

It is recommended that the srand(time(0)) instruction is on the first line of main(). Never use srand(time(0)) again during the program.

Let’s write the complete code and execute it.

Press + to interact
#include <iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
int main()
{
srand( time(0) );
cout << "Random numbers sequence: \n\t";
for(int i=1; i<10; i++)
cout << rand() << " " ;
return 0;
}

Run the above program multiple times and see the output. Every time, it will generate a random seed and random number.

That’s it, we’re done!

Summary

In this lesson, we learned the working mechanism of the random number generation inside the rand() function and implemented it in one possible way. Moreover, we learned why the rand() function always generates the same sequence, unless given a random seed by using the srand(int) function. We also learned the functionality of the time(0) function and used time(0) as the seed in our program to yield random sequences.