Navigation



5.9 — Random number generation

The ability to generate random numbers can be useful in certain kinds of programs, particularly in games, statistics modeling programs, and scientific simulations that need to model random events. Take games for example — Without random events, monsters would always attack you the same way, you’d always find the same treasure, the dungeon layout would never change, etc… and that would not make for a very good game.

So how do we generate random numbers? In real life, we often generate random results by doing things like flipping a coin, rolling a dice, or shuffling a deck of cards. These events involve so many physical variables (eg. gravity, friction, air resistance, momentum, etc…) that they become almost impossible to predict or control, and produce results that are for all intents and purposes random.

However, computers aren’t designed to take advantage of physical variables — your computer can’t toss a coin, throw a dice, or shuffle real cards. Computers live in a very controlled electrical world where everything is binary (false or true) and there is no in-between. By their very nature, computers are designed to produce results that are as predictable as possible. When you tell the computer to calculate 2 + 2, you ALWAYS want the answer to be 4. Not 3 or 5 on occasion.

Consequently, computers are generally incapable of generating random numbers. Instead, they must simulate randomness, which is most often done using pseudo-random number generators.

A pseudo-random number generator (PRNG) is a program that takes a starting number (called a seed), and performs mathematical operations on it to transform it into some other number that appears to be unrelated to the seed. It then takes that generated number and performs the same mathematical operation on it to transform it into a new number that appears unrelated to the number it was generated from. By continually applying the algorithm to the last generated number, it can generate a series of new numbers that will appear to be random if the algorithm is complex enough.

It’s actually fairly easy to write a PRNG. Here’s a short program that generates 100 pseudo-random numbers:

#include <stdafx.h>
#include <iostream>
using namespace std;

unsigned int PRNG()
{
    // our initial starting seed is 5323
    static unsigned int nSeed = 5323;

    // Take the current seed and generate a new value from it
    // Due to our use of large constants and overflow, it would be
    // very hard for someone to predict what the next number is
    // going to be from the previous one.
    nSeed = (8253729 * nSeed + 2396403);

    // Take the seed and return a value between 0 and 32767
    return nSeed  % 32767;
}

int main()
{
    // Print 100 random numbers
    for (int nCount=0; nCount < 100; ++nCount)
    {
        cout << PRNG() << "\t";

        // If we've printed 5 numbers, start a new column
        if ((nCount+1) % 5 == 0)
            cout << endl;
	}
}

The result of this program is:

20433	22044	9937	30185	29341
14783	29730	8430	3076	28768
18053	16066	26537	100	30493
4943	19511	19251	6669	32117
31575	3373	32383	30496	12710
23999	11929	5425	9938	12107
28541	1938	3450	20283	16726
6440	4938	26094	24391	12248
24803	30416	16244	19590	6644
24646	4873	2841	23831	23476
17958	8827	17400	32129	32760
25744	25405	13591	8859	15932
19086	19666	19265	14179	1165
27168	20996	29427	5857	3434
18964	11980	564	4620	400
17362	16934	11889	419	9714
19808	29699	3694	25612	5512
20256	10009	10247	1860	1846
1487	14030	2615	16035	8107
28736	267	29395	9438	20294

Each number appears to be pretty random with respect to the previous one. As it turns out, our algorithm actually isn’t very good, for reasons we will discuss later. But it does effectively illustrate the principle of PRNG number generation.

Generating random numbers in C++

C (and by extension C++) comes with a built-in pseudo-random number generator. It is implemented as two separate functions that live in the cstdlib header:

srand() sets the initial seed value. srand() should only be called once.

rand() generates the next random number in the sequence (starting from the seed set by srand()).

Here’s a sample program using these functions:

#include <stdafx.h>
#include <iostream>
#include <cstdlib> // for rand() and srand()
using namespace std;

int main()
{
    srand(5323); // set initial seed value to 5323

    // Print 100 random numbers
    for (int nCount=0; nCount < 100; ++nCount)
    {
        cout << rand() << "\t";

        // If we've printed 5 numbers, start a new column
        if ((nCount+1) % 5 == 0)
            cout << endl;
	}
}

Here’s the output of this program:

17421	8558	19487	1344	26934
7796	28102	15201	17869	6911
4981	417	12650	28759	20778
31890	23714	29127	15819	29971
1069	25403	24427	9087	24392
15886	11466	15140	19801	14365
18458	18935	1746	16672	22281
16517	21847	27194	7163	13869
5923	27598	13463	15757	4520
15765	8582	23866	22389	29933
31607	180	17757	23924	31079
30105	23254	32726	11295	18712
29087	2787	4862	6569	6310
21221	28152	12539	5672	23344
28895	31278	21786	7674	15329
10307	16840	1645	15699	8401
22972	20731	24749	32505	29409
17906	11989	17051	32232	592
17312	32714	18411	17112	15510
8830	32592	25957	1269	6793

The range of rand()

rand() generates pseudo-random integers between 0 and RAND_MAX, a constant in cstdlib that is typically set to 32767.

Generally, we do not want random numbers between 0 and RAND_MAX — we want numbers between two other values, which we’ll call nLow and nHigh. For example, if we’re trying to simulate the user rolling a dice, we want random numbers between 1 and 6.

It turns out it’s quite easy to take the result of rand() can convert it into whatever range we want:

// Generate a random number between nLow and nHigh (inclusive)
unsigned int GetRandomNumber(int nLow, int nHigh)
{
    return (rand() % (nHigh - nLow + 1)) + nLow;
}

PRNG sequences

If you run the rand() sample program above multiple times, you will note that it prints the same result every time! This means that while each number in the sequence is seemingly random with regards to the previous ones, the entire sequence is not random at all! And that means our program ends up totally predictable (the same inputs lead to the same outputs every time). There are cases where this can be useful or even desired (eg. you want a scientific simulation to be repeatable, or you’re trying to debug why your random dungeon generator crashes).

But often, this is not what is desired. If you’re writing a game of hi-lo (where the user has 10 tries to guess a number, and the computer tells them whether their guess is too high or to low), you don’t want the program picking the same numbers each time. So let’s take a deeper look at why this is happening, and how we can fix it.

Remember that each number in a PRNG sequence is generated from the previous number, in a deterministic way. Thus, given any starting seed number, PRNGs will always generate the same sequence of numbers from that seed as a result! We are getting the same sequence because our starting seed number is always 5323.

In order to make our entire sequence randomized, we need some way to pick a seed that’s not a fixed number. The first answer that probably comes to mind is that we need a random number! That’s a good thought, but if we need a random number to generate random numbers, then we’re in a catch-22. It turns out, we really don’t need our seed to be a random number — we just need to pick something that changes each time the program is run. Then we can use our PRNG to generate a unique sequence of pseudo-random numbers from that seed.

The commonly accepted method for doing this is to enlist the system clock. Each time the user runs the program, the time will be different. If we use this time value as our seed, then our program will generate a different sequence of numbers each time it is run!

C comes with a function called time() that returns the number of seconds since midnight on Jan 1, 1970. To use it, we merely need to include the ctime header, and then initialize srand() with a call to time(0):

#include <stdafx.h>
#include <iostream>
#include <cstdlib> // for rand() and srand()
#include <ctime> // for time()
using namespace std;

int main()
{

    srand(time(0)); // set initial seed value to system clock
    for (int nCount=0; nCount < 100; ++nCount)
    {
        cout << rand() << "\t";

        if ((nCount+1) % 5 == 0)
            cout << endl;
	}
}

Now our program will generate a different sequence of random numbers every time!

What is a good PRNG?

As I mentioned above, the PRNG we wrote isn’t a very good one. This section will discuss the reasons why. It is optional reading because it’s not strictly related to C or C++, but if you like programming you will probably find it interesting anyway.

In order to be a good PRNG, the PRNG needs to exhibit a number of properties:

First, the PRNG should generate each number with approximately the same probability. This is called distribution uniformity. If some numbers are generated more often than others, the result of the program that uses the PRNG will be biased!

For example, let’s say you’re trying to write a random item generator for a game. You’ll pick a random number between 1 and 10, and if the result is a 10, the monster will drop a powerful item instead of a common one. You would expect a 1 in 10 chance of this happening. But if the underlying PRNG is not uniform, and generates a lot more 10s than it should, your players will end up getting more rare items than you’d intended, possibly trivializing the difficulty of your game.

Generating PRNGs that produce uniform results is difficult, and it’s one of the main reasons the PRNG we wrote at the top of this lesson isn’t a very good PRNG.

Second, the method by which the next number in the sequence shouldn’t be obvious or predictable. For example, consider the following PRNG algorithm: nNum = nNum + 1. This PRNG is perfectly uniform, but it’s not very useful as a sequence of random numbers!

Third, the PRNG should have a good dimensional distribution of numbers. This means it should return low numbers, middle numbers, and high numbers seemingly at random. A PRNG that returned all low numbers, then all high numbers may be uniform and non-predictable, but it’s still going to lead to biased results, particularly if the number of random numbers you actually use is small.

Fourth, all PRNGs are periodic, which means that at some point the sequence of numbers generated will eventually begin to repeat itself. As mentioned before, PRNGs are deterministic, and given an input number, a PRNG will produce the same output number every time. Consider what happens when a PRNG generates a number it has previously generated. From that point forward, it will begin to duplicate the sequence between the first occurrence of that number and the next occurrence of that number over and over. The length of this sequence is known as the period

For example, here are the first 100 numbers generated from a PRNG with poor periodicity:

112	9	130	97	64
31	152	119	86	53
20	141	108	75	42
9	130	97	64	31
152	119	86	53	20
141	108	75	42	9
130	97	64	31	152
119	86	53	20	141
108	75	42	9	130
97	64	31	152	119
86	53	20	141	108
75	42	9	130	97
64	31	152	119	86
53	20	141	108	75
42	9	130	97	64
31	152	119	86	53
20	141	108	75	42
9	130	97	64	31
152	119	86	53	20
141	108	75	42	9

You will note that it generated 9 as the second number, and 9 again as the 16th number. The PRNG gets stuck generating the sequence in-between these two 9′s repeatedly: 9-130-97-64-31-152-119-86-53-20-141-108-75-42-(repeat).

A good PRNG should have a long period for all seed numbers. Designing an algorithm that meets this property can be extremely difficult — most PRNGs will have long periods for some seeds and short periods for others. If the user happens to pick that seed, then the PRNG won’t be doing a good job.

Despite the difficulty in designing algorithms that meet all of these criteria, a lot of research has been done in this area because of it’s importance to scientific computing.

rand() is a mediocre PRNG

The algorithm used to implement rand() can vary from compiler to compiler, leading to results that may not be consistent across compilers. Most implementations of rand() use a method called a Linear Congruential Generator (LCG). If you have a look at the first example in this lesson, you’ll note that it’s actually a LCG, though one with intentionally poorly picked bad constants. LCGs tend to have shortcomings that make them not good choices for certain kinds of problems.

One of the main shortcomings of rand() is that RAND_MAX is usually set to 32767 (essentially 16-bits). This means if you want to generate numbers over a larger range (eg. 32-bit integers), the algorithm is not suitable. Also, rand() isn’t good if you want to generate random floating point numbers (eg. between 0.0 and 1.0), which is often useful when doing statistical modelling. Finally, rand() tends to have a relatively short period compared to other algorithms.

That said, rand() is entirely suitable for learning how to program, and for programs in which a high-quality PRNG is not a necessity. For such applications, I would highly recommend Mersenne Twister, which produces great results and is relatively easy to use.

6.1 — Arrays (Part I)
Index
5.8 — Break and Continue

57 comments to 5.9 — Random number generation

  • hi Alex, it’s good to see you’ve put in something about random numbers,now I can make games with random numbers….
    thanks for the great tutorial alex

  • Ivan

    “Prev/Next Posts” at the top of the page points back to a higher numbered section (15.6), and forward to something else.

    • Yeah, that one is generated automatically by my wordpress theme and is set to display articles in the order they were written. This 5.9 section was written out of order, hence the weirdness. I’ll look into removing it.

  • Pathik
    
    #include <stdafx.h>
    #include <iostream>
    #include <cstdlib> // for rand() and srand()
    #include <ctime> // for time()
    using namespace std;
    
    int main()
    {
    
        srand(time()); // set initial seed value to system clock
        for (int nCount=0; nCount < 100; ++nCount)
        {
            std::cout << rand() << "t";
    
            if ((nCount+1) % 5 == 0)
                std::cout << std::endl;
    	}
    }
    

    This code in visual c++ 2005 express edition gives this error at compile time:

    ‘error C2661: ‘time’ : no overloaded function takes 0 arguments’

  • diyon

    Hi, I’m new to C++. and would like to know how to write a programe to generate random numbers uniformly distributed between 0 and 1.
    Thank you,

    • rand() generates numbers between 0 and RAND_MAX. So to generate numbers between 0 and 1, simply divide the result of rand() by RAND_MAX (make sure to use a cast to cast the result to a double, otherwise you’ll get integer division).

      eg.

      double dUniform = static_cast<double>(rand()) / RAND_MAX;
      
  • vandana

    hi,

    its really good informaion about random no.
    but i have one doubt if ((nCount+1) % 5 == 0) this statement return some no.,
    but rand() fuction generate random no., why you wrote this statement.
    plz clear my doubt.

    Tahnking you.

  • Spock

    Hey Alex,

    Your codes above have the

    using namespace std;

    declared, yet you also use (for example):

    std::cout << rand() << "\t";   

    I thought that the first declaration negated the need for the std:: statement.

    Thanks!

  • Abby

    Is it possible to create a random statement for a group of words that I come up with, not just random numbers?

  • Sam

    Hi Alex,

    I am trying to implement a fighting system into a game I am making. I need to use random numbers to determine if you hit or miss and then how much damage you do. I just am not sure how to do that. I read what you wrote about the random numbers and I am kinda new at c++. so far what I have is (minus all the other code)

    #include iostream
    #include cstdlib
    #include ctime

    (sorry had to remove so they would show)

    int main(){

    int hit = rand ();

    for (int hit; hit < 100; ++hit)
    {
    if ( hit less than 100 and greater than 50 ) {
    cout<<”You hit.”

    }

    and thats what I have so far because I don’t know if I should keep going if I need to fix something. (PS. sorry for using words when i tried posting it did stuff to the code)

    • Jason

      Hey Sam,

      Use this code:

      #include
      #include
      #include //Needed to get current time

      int main()
      {
      //Seeds the random number genarator with the current time
      //so you get different result every time your program runs
      srand( time(NULL) );

      //Chooses a random number between 0-100 using %(Mod)
      int hit = rand() % 100;

      //If hit is 50-100 than hit, else miss.
      if ( (hit>=50) && (hit<=100) )
      cout << ”You hit.”;
      else
      cout << “You missed.”;
      }

  • Dan

    Hey Alex, thanks for making the great tutorials.

    I’m wondering if there’s any way to generate 30 random numbers and store them in an array. I’m able to generate a random number and store it in an array, but whenever I try to access the array every single indexed number in it is the same random number. I’m thinking that this is perhaps because the random number is based on the system clock and all 30 numbers are created at the same time?

    • I don’t see any reason why what you are doing wouldn’t work. If you initialize the array using a loop like this:

      for (int nCount=0; nCount < nArraySize; ++nCount)
          nArray[nCount] = rand() % 100;
      

      you should get a different number in each slot.

      If you’re not, then I suspect you’re either initializing your array incorrectly or your rand() really isn’t returning random numbers for some reason.

  • Markos

    Hi , thank you for this information , but i have a question. Is there a way that i can generate a random number between two ranges of numbers( like, i want to generate a random number that is in (0 to 200) or (400 to 1300) ).

    with best wishes

    • Josh Browning

      I’m not sure if there’s a better way to do this, but you could generate a random boolean (i.e. rand()%2) and then use an if statement to determine which range to use. So, for example, if the random boolean is 0, then pick a random number between 0 to 200, else pick one between 400 to 1300. If you want one range to show up more often than the other, just pick a random integer first (maybe from 0 to 9) and have only 0 and 1 lead to the range 400 to 1300. Then, 80% of the time you will have a random number between 0 to 200, and 20% between 400 to 1300 (if your RNG is good).

  • once we needed to use the actual eth packet numbers and some system data to generate a rand number in an embedded device…

    in some cases it’s really difficult to generate (so-called)random numbers.

  • Why do you need to declare nSeed with the static key word with this? I don’t see the point in needing its file scope.

    • baldo

      nSeed is a local variable for the PRNG function. The static keyword has another meaning when used for local variables. In this case, nSeed variable “retains it’s value even after the scope in which it has been created has been exited! Fixed duration variables are only created (and initialized) once, and then they are persisted throughout the life of the program.” See more here: Lesson 4.3. the static keyword

  • See: http://www.number.com.pt/index.html

    x_n+1 = frac(s+nx_n)

    This algorithm is very elegant, fast and with good qualities.

  • Hank

    I have an issue with your mapping implementation (the GetRandomNumber function). It’s fine for small ranges like the dice example, but for larger target ranges, you can get serious uniformity issues. For example, let’s say you want a random number between 0 and 21,844 (about 2/3 of rand()’s RAND_MAX). With GetRandomNumber, for numbers that already fall in the target range, you get a 1-to-1 mapping (0 becomes 0, 1 becomes 1, etc.), then for the rest of the domain of rand(), the output essentially starts over at 0 and overlaps onto the first half of the target range. Therefore, you’re twice as likely to get a number between 0 and 10,922 as you are to get one between 10,923 and 21,844, when the probabilities should be equal! Thus I’d recommend instead just using *, /, + and – to convert (probably need to cast to a float first, then truncate).

  • I dont understand in your first example how

    return nSeed % 32767;

    is going to give us a number between 0 and 32767.Isnt % supposed to give the remainder of the division?And since nSeed is always the same number,since we do the same arithetic operations with it each time,wont the remainder be the same,resulting in the return value being the same?

    I hope you understand my question ;P

  • BlackCAT

    Hi, im new to programming in C++…
    I’ve been trying to think of an algorithm
    but just cant!
    How do i write code that;
    //select 2 numbers randomly out of 6 constant numbers
    //which is
    //9, 14, 19, 25, 29, 37
    Pls, need help ASAP!
    Thanks a lot in advance.

  • .......

    Any way to create a random char?

  • RAMI

    hi when i run my program it give me a random number but when i rerun it agian it give me the same number i want each time i run the program i want it to give me a diffrent number

  • Hi Alex, could you please explain how this works?

    // Generate a random number between nLow and nHigh (inclusive)
    unsigned int GetRandomNumber(int nLow, int nHigh)
    {
        return (rand() % (nHigh - nLow + 1)) + nLow;
    }
    • copier1

      nHigh-nLow+1 gives the size of the range. I.E. 41 to 94 has 54 possible numbers (inclusive). 94-41+1=54. This generates a random number from 0 to 53. Adding the nLow value puts that number into the desired range.

  • Alex, you have a v good understanding of the field which you deal with. Thanks for all these detailed tutorials. Keep up the good work.
    Thankyou Alex.

  • Nathan
    using namespace std;
    
    int nNum;
    bool check;
    
    int main()
    {
        srand(time(0)); // set initial seed value to system clock
    	int nNum = rand();
        cout << nNum;
    	while (check() == false)
    	{
    		check();
    	}
    }
    
    bool check()
    {
    	int nCheck;
    	cin << nCheck;
    	if (nCheck == nNum)
    	{
    		cout << "Correct!" << endl;
    		return 1;
    	}
    	else if (nCheck < nNum)
    	{
    		cout << "Too Low." << endl;
    		return 0;
    	}
    	else if (nCheck > nNum)
    	{
    		cout << "Too High." << endl;
    		return 0;
    	}
    }
    

    Hey I don’t know if anyone could help me but I’m trying to make the game Alex mentioned called Hi-Lo and I get the errors

    "main.cpp(15) : error C2064: term does not evaluate to a function taking 0 arguments" 
    
    and 
    
    "main.cpp(15) : fatal error C1903: unable to recover from previous error(s); stopping compilation"

    Can anyone tell me what I did wrong?

  • Erik

    Hi Alex!
    I want to start learning C++,and I have an idea of a program,what I want to create. I want to randomize some sentences(for example:you push a button of a program,and it shows a sentence:Welcome to my world!then push again,and shows:How are you?) Is it possible to do with this tutorial?

    Hope to hear from you soon!

  • Gigith

    Why is stdafx.h included?
    I could understand you breaking GCC/MinGW/Other compatibility if you had to, but it doesn’t look like it even gets used in those examples.

  • Jjtricky

    I really don’t get this line:

     if ((nCount+1) % 5 == 0) 

    Surely, this would break the line after the fourth number, as:

    nCount=4
    (4+1)/5 
    
    5/5 = 1.0
    

    Therefore, the line is ended

  • Jack Sparrow II

    My question is how do I generate random numbers without generating the same ones multiple times?

  • THE TERMINATOR

    HELP!!! MY PRNG KEEPS PRINTING “4 8 15 16 23 42″ NO MATTER WHAT I DO!!!!!

  • Just a quick question, what will happen with the function time() in 69 years from 1970 (year 2039). Will every program in the world that uses time() crash? I imagine no one tought this would be an issue in 1970 xD.

  • copier1

    I’m sorry, not usually picky about grammar. But “dice” is the plural form of the word. If you want the singular version, it’s “die”.

  • cubbi

    While commonly used in bad textbooks, the % operator should NOT be used to limit the range of values produced by std::rand(): it results in a non-uniform distribution. If you must use std::rand(), divide by RAND_MAX (cast to double).

  • jonathonjones

    Minor nitpick: in the examples, you have the following comment:

    // If we’ve printed 5 numbers, start a new column

    But actually, you’re starting a new row, not a new column.

  • Dragon

    Where do you put the code that keeps the application up for more than a millisecond?

  • coyote

    Just as a heads up, I noticed that when I ran the last program for random numbers I did get output that was as high as: 2033645517. This is on a linux box so it might be that different systems/compilers have different defaults for the RAND_MAX constant.

  • Jupi

    In the function:

    unsigned int GetRandomNumber(int nLow, int nHigh)
    {
    return (rand() % (nHigh - nLow + 1)) + nLow;
    }

    I don’t understand why those operations are being done to the random number. I also don’t get how using the modulus operator can change the maximum value for a random number (as in the first example: return nSeed % 32767;). Will someone explain please?

  • hypehuman

    Alex, your tutorial is awesome! I’ve been using it for a while and having a lot of fun. I managed to make a program that intelligently plays Minesweeper because of your tutorial!

    Anyway, I think this is a mistake:

    “Second, the method by which the next number in the sequence shouldn’t be obvious or predictable.”

    should be:

    “Second, the method by which the next number in the sequence is generated shouldn’t be obvious or predictable.”

  • So I tried to make a random number generator between 1 and 13. And at the end when you guess correctly it shows how many times you guessed. It is funny though because it seems whenever I enter 3 into the program it comes out blank and ends the program.

    Here is the code:
    #include
    #include
    #include

    using namespace std;

    int counter=0;

    unsigned int getRandom(int nHigh, int nLow){
    return (rand() % (nHigh – nLow + 1)) + nLow;
    }
    int main(){
    int x, y;
    x=1;
    y=13;
    int nGuess;

    cout << "Enter a gues between 1 and 6: " <> nGuess;
    getRandom(y,x);
    if (nGuess < getRandom(y,x)){
    cout << "too low try again" < getRandom(y,x)){
    cout << "Too high try again" << endl;
    counter=counter+1;
    main();
    }
    else if (nGuess == getRandom(y,x)){
    cout << "Congradulations!" << endl;
    cout << "Number of Guesses: " << counter << endl;

    }
    system ("PAUSE");
    return 0;
    }

  • Thanks. Your tutorials are always very explanatory. But you don’t seem to have introduced the idea of introducing a bit true randomness using time() function or by using current date and time. I have tried the same on my blog.

You must be logged in to post a comment.