Search

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 (e.g. 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 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:

The result of this program is:

23070   27857   22756   10839   27946
11613   30448   21987   22070   1001
27388   5999    5442    28789   13576
28411   10830   29441   21780   23687
5466    2957    19232   24595   22118
14873   5932    31135   28018   32421
14648   10539   23166   22833   12612
28343   7562    18877   32592   19011
13974   20553   9052    15311   9634
27861   7528    17243   27310   8033
28020   24807   1466    26605   4992
5235    30406   18041   3980    24063
15826   15109   24984   15755   23262
17809   2468    13079   19946   26141
1968    16035   5878    7337    23484
24623   13826   26933   1480    6075
11022   19393   1492    25927   30234
17485   23520   18643   5926    21209
2028    16991   3634    30565   2552
20971   23358   12785   25092   30583

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:

std::srand() sets the initial seed value to a value that is passed in by the caller. srand() should only be called once at the beginning of your program. This is usually done at the top of main().

std::rand() generates the next random number in the sequence. That number will be a pseudo-random integer between 0 and RAND_MAX, a constant in cstdlib that is typically set to 32767.

Here’s a sample program using these functions:

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

PRNG sequences and seeding

If you run the std::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 (e.g. 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 too 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 std::time(nullptr) (or std::time(0) if your compiler is pre-C++11).

Here’s the same program as above, using a call to time() as the seed:

Now our program will generate a different sequence of random numbers every time! Run it a couple of times and see for yourself.

Generating random numbers between two arbitrary values

Generally, we do not want random numbers between 0 and RAND_MAX -- we want numbers between two other values, which we’ll call min and max. For example, if we’re trying to simulate the user rolling a die, we want random numbers between 1 and 6 (pedantic grammar note: yes, die is the singular of dice).

Here’s a short function that converts the result of rand() into the range we want:

To simulate the roll of a die, we’d call getRandomNumber(1, 6). To pick a randomized digit, we’d call getRandomNumber(0, 9).

Optional reading: How does the previous function work?

The getRandomNumber() function may seem a little complicated, but it’s not too bad.

Let’s revisit our goal. The function rand() returns a number between 0 and RAND_MAX (inclusive). We want to somehow transform the result of rand() into a number between min and max (inclusive). This means that when we do our transformation, 0 should become min, and RAND_MAX should become max, with a uniform distribution of numbers in between.

We do that in five parts:

  1. We multiply our result from std::rand() by fraction. This converts the result of rand() to a floating point number between 0 (inclusive), and 1 (exclusive).

    If rand() returns a 0, then 0 * fraction is still 0. If rand() return RAND_MAX, then RAND_MAX * fraction is RAND_MAX / (RAND_MAX + 1), which is slightly less than 1. Any other number returned by rand() will be evenly distributed between these two points.

  2. Next, we need to know how many numbers we can possibly return. In other words, how many numbers are between min (inclusive) and max (inclusive)?

    This is simply (max - min + 1). For example, if max = 8 and min = 5, (max - min + 1) = (8 - 5 + 1) = 4. There are 4 numbers between 5 and 8 (that is, 5, 6, 7, and 8).

  3. We multiply the prior two results together. If we had a floating point number between 0 (inclusive) and 1 (exclusive), and then we multiply by (min - max + 1), we now have a floating point number between 0 (inclusive) and (max - min + 1) (exclusive).
  4. We cast the previous result to an integer. This removes any fractional component, leaving us with an integer result between 0 (inclusive) and (max - min) (inclusive).
  5. Finally, we add min, which shifts our result to an integer between min (inclusive) and max (inclusive).

Optional reading: Why don’t we use the modulus operator (%) in the previous function?

One of the most common questions readers have submitted is why we use division in the above function instead of modulus (%). The short answer is that modulus tends to be biased in favor of low numbers.

Let’s consider what would happen if the above function looked like this instead:

Seems similar, right? Let’s explore where this goes wrong. To simplify the example, let’s say that rand() always returns a random number between 0 and 9 (inclusive). For our sample case, we’ll pick min = 0, and max = 6. Thus, max - min + 1 is 7.

Now let’s calculate all possible outcomes:

0 + (0 % 7) = 0
0 + (1 % 7) = 1
0 + (2 % 7) = 2
0 + (3 % 7) = 3
0 + (4 % 7) = 4
0 + (5 % 7) = 5
0 + (6 % 7) = 6

0 + (7 % 7) = 0
0 + (8 % 7) = 1
0 + (9 % 7) = 2

Look at the distribution of results. The results 0 through 2 come up twice, whereas 3 through 6 come up only once. This method has a clear bias towards low results. By extension, most cases involving this algorithm will behave similarly.

Now lets take a look at the result of the getRandomNumber() function above, using the same parameters as above (rand() returns a number between 0 and 9 (inclusive), min = 0 and max = 6). In this case, fraction = 1 / (9 + 1) = 0.1. max - min + 1 is still 7.

Calculating all possible outcomes:

0 + static_cast(7 * (0 * 0.1))) = 0 + static_cast(0) = 0
0 + static_cast(7 * (1 * 0.1))) = 0 + static_cast(0.7) = 0
0 + static_cast(7 * (2 * 0.1))) = 0 + static_cast(1.4) = 1
0 + static_cast(7 * (3 * 0.1))) = 0 + static_cast(2.1) = 2
0 + static_cast(7 * (4 * 0.1))) = 0 + static_cast(2.8) = 2
0 + static_cast(7 * (5 * 0.1))) = 0 + static_cast(3.5) = 3
0 + static_cast(7 * (6 * 0.1))) = 0 + static_cast(4.2) = 4
0 + static_cast(7 * (7 * 0.1))) = 0 + static_cast(4.9) = 4
0 + static_cast(7 * (8 * 0.1))) = 0 + static_cast(5.6) = 5
0 + static_cast(7 * (9 * 0.1))) = 0 + static_cast(6.3) = 6

The bias here is still slightly towards lower numbers (0, 2, and 4 appear twice, whereas 1, 3, 5, and 6 appear once), but it’s much more uniformly distributed.

Even though getRandomNumber() is a little more complicated to understand than the modulus alternative, we advocate for the division method because it produces a less biased result.

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 is generated shouldn’t be obvious or predictable. For example, consider the following PRNG algorithm: num = num + 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 a seed that has a short period, 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 its importance to scientific computing.

std::rand() is a mediocre PRNG

The algorithm used to implement std::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 picked poor constants. LCGs tend to have shortcomings that make them not good choices for most kinds of problems.

One of the main shortcomings of rand() is that RAND_MAX is usually set to 32767 (essentially 15-bits). This means if you want to generate numbers over a larger range (e.g. 32-bit integers), rand() is not suitable. Also, rand() isn’t good if you want to generate random floating point numbers (e.g. 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 perfectly suitable for learning how to program, and for programs in which a high-quality PRNG is not a necessity.

For applications where a high-quality PRNG is useful, I would recommend Mersenne Twister (or one of its variants), which produces great results and is relatively easy to use.

rand() may return the same first value on successive calls on some compilers

The implementation of rand() in Visual Studio and a few other compilers has a flaw -- the first random number generated doesn’t change much for similar seed values. This means that when using time() to seed your random number generator, the first result from rand() won’t change much in successive runs. This problem is compounded by calling getRandomNumber(), which compresses similar inputs into the same output number. The results of successive calls to rand() aren’t impacted.

However, there’s an easy fix: call rand() once and discard the result. Then you can use rand() as normal in your program.

Recommendation: After calling srand(), call rand() once and discard the first result to avoid this issue.

Debugging programs that use random numbers

Programs that use random numbers can be difficult to debug because the program may exhibit different behaviors each time it is run. Sometimes it may work, and sometimes it may not. When debugging, it’s helpful to ensure your program executes the same (incorrect) way each time. That way, you can run the program as many times as needed to isolate where the error is.

For this reason, when debugging, it’s a useful technique to set the random seed (via srand) to a specific value (e.g. 0) that causes the erroneous behavior to occur. This will ensure your program generates the same results each time, making debugging easier. Once you’ve found the error, you can seed using the system clock again to start generating randomized results again.

Random numbers in C++11

C++11 added a ton of random number generation functionality to the C++ standard library, including the Mersenne Twister algorithm, as well as generators for different kinds of random distributions (uniform, normal, Poisson, etc…). This is accessed via the <random> header.

Here’s a short example showing how to generate random numbers in C++11 using Mersenne Twister (h/t to user Fernando):

You’ll note that Mersenne Twister generates random 32-bit unsigned integers (not 15-bit integers like std::rand()), giving a lot more range. There’s also a version (std::mt19937_64) for generating 64-bit unsigned integers!

There’s so much functionality in <random> that it really warrants its own section. We’ll look to cover that in a future lesson in more detail.

5.10 -- std::cin, extraction, and dealing with invalid text input
Index
5.8 -- Break and continue

307 comments to 5.9 — Random number generation

  • David

    Hi Alex. I adjusted the getRandomNumber function to use the Mersenne Twister. Do you think this is the proper way to write it?

  • Isak

    Hello there Alex, I would greatly like some feedback on this (pseudo)random number generator program I made, it uses classes which you cover later on in this series.

    (Note. You said that avoiding use of goto statements is encouraged, i read about the topic online and I can see some very good reason as to not using it, like allowing one to go out of scope and the code can be very hard to follow. But in my code I found that using goto statements here would not be confusing since it's very easily to follow, I'd like your opinion on this Alex!)

    Thanks in advance!

    • Alex

      A few thoughts:
      * You should use enums instead of defines, and you should avoid use of goto. Neither are egregious issues, but since these best practices exist, why not follow them?
      * Your code calls checkGuess() up to 3 times per pass -- you're better off calling it once and stashing the result in a variable, then doing your if/else statements on that.
      * I'm not clear on why the Enemy constructor contains a static PRNG but then you make the user call it explicitly. It might be more intuitive to have the user pass in 0 and 100 and have the constructor pass those into the PRNG to generate a random number for that Enemy.

      Overall, I see a lot of good stuff here. Keep it up.

      • Isak

        Thanks for your input it's greatly appriciated!

        * I assume these practices exists for a reason so I'd better be off using them, thank you!

        * You did mention that doing a function call was computionally expensive right? Is that the reason to avoid this or is it because repetitive code should be avoided, or both?

        * Thank you, your method sounds more straightforward and I will fix that. The reason I made PRNG static is too clarify what you're passing in as an argument.

        Again, thank you so much Alex for your advice, this site is truly awesome!

        • Alex

          On modern systems, function calls aren't that expensive (as long as you're not doing something stupid, like passing large arrays or structs by value). Unless you need your codeto be maximally performant, or you have hundreds or thousands of functions calls happening, it's probably not worth worrying about the cost of a few extra function calls. It's better to keep your code clean, modular, and readable.

  • AMG

    Hi Alex,
    Please correct "Site Index" for few items: Mersenne twister, RAND_MAX, Rand, Seed, Srand. Wrong reference to 1.2. Thank you.

  • Micah

    Looks like the Mersenne Twister has a new version (SFMT) at
    --   http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html   ---

  • Micah

    If you made it this far and didn't know die is singular for dice I'm concerned about you

  • Michael

    Hi Alex,

    why is there a 1.0 in (static_cast<double>(RAND_MAX)+1.0) and also a 1 in (max-min+1)?

    It seems to me that it is unnecessary for normalizing rand().

    Can you explain it in detail? thanks!

    • Alex

      The range of RAND_MAX is typically between 0 and 32767, which is 32768 unique numbers. We add 1.0 to make the fraction 1/32768, not 1/32767.

      Similarly, the count of numbers between min and max (inclusive) is (max - min + 1). For example, if min = 5 and max = 8, max - min + 1 is 4. Indeed, there are 4 numbers between 5 and 8: 5, 6, 7, and 8.

      • Michael

        Suppose we have fraction as

        and

        rand() is [0,RAND_MAX](inclusive), and RAND_MAX can reach up to 32767.

        then rand()*fraction would be [0,1](inclusive), and (max-min)*(rand()*fraction) would be [0, max-min].
        The return value then would be from [min, max] and evenly distributed, which is what we want.

        Is the train of thought right?

        • Alex

          Yes, it's the right train of thought, but your algorithm (lacking the + 1.0 and +1) has a flaw. Because floating point numbers are truncated (not rounded) when converted to integers, max will only occur if RAND_MAX is picked for rand() (otherwise, rand() * fraction < 1.0, which means min + ((max - min) * (rand() * fraction)) would be less than max, and thus truncated). This means max will potentially show up less than other numbers. What we want is to ensure an equal distribution. We use RAND_MAX + 1.0 to ensure fraction * rand() never reaches 1.0, so that all of the numbers between min and max have an equal probability of occurrence.

  • Gunjan Jhawar

    Doubt in the text above: Here’s a short program that generates 100 pseudo-random numbers. In this return seed  % 32768; will it always return a single digit.
    If count is 1 and we have more one digit then we can get like six digits even when count< 5.

    What I mean is: if count = 1 by modulus we get 23, then count = 2, we get 21, then count = 3 we get 2 then by count = 4 we get 45 then count =5 we get 3
    So our first number would be 23212453 but that is not a five digit number.

    • Alex

      > In this return seed % 32768; will it always return a single digit.

      No, it will return a number between 0 and 32767, as the comment indicates.

      Count is just used to loop 5 times, it has nothing to do with the seed value.

  • Kushagra

    can this type of code used for clock in game?

    #include  <iostream>
    #include <ctime>

    int fg()
    {
        int x = static_cast<unsigned int >(time(0));
        return x;
    }
    int main()

    {
        
    const    int y = fg();
        for (; fg() < ( y+3);)
        {}
        std::cout << " Time up" ;
        return 0;
    }

  • JimD

    A bit of a strange happening in linux code::blocks 13.12 (gcc compiler set to c++11) with the random number function given above. Unless I include a static_cast to ‘double’ for the integer term in the final formula it just produces 1 all the time. The reason seems to be that including integers in the calculation makes it revert to an integer calculation with result zero, regardless of the random number generated. This is the modified code I used to get it working (note the additional ‘static_cast<double> in there:

    I tried it in Visual Studio and (as expected) the original works fine. But it also works fine in code::blocks 16.01 in Windows 10, with the same settings as I used in Linux. I’m puzzled.

    • Alex

      This is really strange to me. Doing arithmetic with a double operand and an integer operand should produce a double result. 1.0 is a double operand in this case, and should be sufficient to cause the program to do floating point division rather than integer division...

      • JimD

        Yes, very odd. After reading your response I had an idea to try something slightly different from the 'static_cast' workaround:

        This line (with the literal number one expressed unmistakably as a double) works correctly on my linux set up. So it's definitely to do with the compiler interpreting that calculation in the brackets as an integer and applying it to the whole expression.

        • Alex

          I wonder if this is a result of max - min + 1 being evaluated first, and then being multiplied by rand(), which is an int, resulting in an int result that could overflow. I've updated the sample code to ensure that rand() is multiplied by fraction to produce a floating point result before being multiplied by max - min + 1. I'm curious if that fixes your issue or not.

          • JimD

            Changed it to:

            And it works correctly. Nice one!

            So the question in my mind is, how come gcc on linux is treating formulae differently to gcc on windows (with the same settings on both as far as I can see). I had assumed they were the same programme, just compiled onto different target systems.

            • Alex

              I'm not sure, I would have assumed they're the same as well. But since they're generating code differently, maybe the way they're configured causes this expression to evaluate slightly differently...

  • Frodo

    Hi,
    In the last example (with Mersenne Twister) it seems that main does not return an int.

  • Luhan

    Im trying to understand this code, so i was thinking:

    1)The fractions is to round down the number?

    2)Why do you need to put min inside the parenthesis if you're going to sum 1 right after it?

    • Alex

      The algorithm works by generating a random number between 0 and RAND_MAX. We then use the fraction to convert that to a number between 0 and 1, because that's easier to work with. We then multiply and shift the number between 0 and 1 to evenly distribute between min and max.

      min is inside the parenthesis so that (max - min + 1) all get multiplied by rand and fraction.

      • Luhan

        1) I don't understand one thing, if rand() is equal to, for example,  '32.700', so the result of multiplication of max would be equal to 196.200, and after it the multiplication with fraction would be equal to 5,987548828125, wouldn't that aproximate to 6, and + min the result wouldn't be 7? (considerating that min would be 1, so it would be canceled with the +1)

        2) Just one more thing, how (max - min + 1) would all be multiplied, because they are inside a parenthesis, they wouldn't be calculated first and after the result would be multiplied by rand() and fraction?

        • Alex

          1) No, numbers don't get approximated to the nearest integer. They always get rounded down (truncated). So 5.987 becomes 5, and the +1 makes it 6.
          2) Yes, max - min + 1 is calculated first, this is multiplied by rand() and fraction, and then min is added. This is standard mathematical precedence.

  • Lucas F.

    Hi Alex, first of all congratulations on these awesome tuturials! (even though I'm only less than halfway through)
    I'm not sure whether anyone in the comments posted this before, but (I think) I made a getRandomNumber function based on the one you presented that works regardless of the sign of its parameters (it can handle a "negative dice" or even one with values from -2 to 3)

    Here it is:

    For example the  case where min < 0 and max > 0 would otherwise be complicated to handle because of symmetrical rounding toward 0 by the cast.

    • Alex

      Interesting idea, I hadn't thought about the impacts of rounding with negative numbers. Seems like that could increase the prevalence of 0 coming up when min 0. I'll have to look into a good solution for this. Yours is close, but I think it might be flawed in that you could overflow max.

      • Lucas F.

        Thanks for the advice! To adress overflow I came up with the improved function below.

        Might this actually work?
        Another possibly shorter solution in your original compact function would be to force the program to round correctly by subtracting 1 form the final double result before rounding.

        However this introduces the problem of of accurate calculation with doubles.

        • Lucas F.

          Can't edit anymore so new post(ignore the previous full of typos, bad format and 2 fatal flaws due to unsigned integers insted of signed)

          Thanks for the advice! To adress overflow I came up with the improved function below.

              

          However if I try it with range from -32768 to 32767 (65536 possible outcomes, which is double that of rand, 32768)) I can only get even integers (32768)!(fraction advances in 1/32768, and 65536/32768 = 2) Maybe it's a fundamental principle that we can't extend a choice among 32768 values to one among 65536 values?
          Otherwise my function should come with the warning that the range (max - min + 1) cannot be > (32768)        

          Another thing that came to my mind is to bypass this limitation by calling rand() twice with a brutally simple function:

                  

          Another much shorter solution in your original compact function would be to force the program to round correctly by subtracting 1 form the final double result before rounding.

          However this introduces the problem of accurate calculation with doubles, and the only values I can get (again with min = -32768 and max = 32767) are odd for negatives and even with non-negatives! Again one call to rand() doesn't seem enough to enable a choice in a range wider than that of rand() itself.
          Can't wait to hearing what do you think about these.

          • Alex

            This is really good thinking on your part. Since numbers will be generated between 0 and RAND_MAX, our min and max can’t be more than RAND_MAX apart, otherwise we’ll not have coverage for all numbers (this is why you saw all even numbers when you set the range to -32767 and 32767). If you need a wider range of random numbers, you’ll need to use some other method (which isn’t a bad idea anyway).

            After thinking about things for a bit, I believe I’ve found a solution that handles both positive and negative numbers adequately:

            This method essentially calculates the result from 0 to max-min+1 to avoid the negative number rounding issue and then shifts it by min. We can’t run into overflow here given that the algorithm doesn’t work if min and max are more than RAND_MAX apart anyway. So we might as well just treat that as a limitation of the function rather than work around it in crazy ways.

  • Taksh

    Hey Alex,

    You wrote:

    I was wondering whether this would be better.

    I replaced initial value of count to 1 and instead of < 100, I wrote =< 100.
    Wouldn't this be less complicated as we longer require confusing expressions such as (count + 1) % 5?

  • The Perplexed Programmer

    Hello Alex!
    The following program is a quiz consisting of 5 questions. It works perfectly!(Thank God!). Is is possible to ask a question at random?
    Thanks!
    (Feel free to quiz yourself, and do tell me how much you scored!)

    • Alex

      > Is is possible to ask a question at random?

      Definitely. Pick a random number between 0 and the number of questions-1, and then ask the user that question.

      • The Perplexed Programmer

        Thank you!
        I'm sorry for being annoying, but could you please write the code for it? I didn't quite get it. Thanks again !!

        • Alex

          Rather than do that, I'll outline the procedure and you can write the code as an exercise. I'm assuming you want to only ask the user one random question each execution of the program.

          Step 1) Write a separate function for each question and answer. Return true if the user got it right, and false otherwise.
          Step 2) In main, pick a random number between 0 and 4.
          Step 3) Switch on the random number, and call the appropriate function.
          Step 4) Print the user's score.

          If you want to call all 5 questions in a random order, that's a little more complex. The best way to do that is to use the following procedure:
          1) Initialize an array of 5 elements with values 0 through 4.
          2) Iterate through each element of the array (with index i)
          3) Pick a random number between 0 and 4 (we'll call this r)
          4) Swap the elements with index i and r.

          At that point, you now have an array where the indices have been randomized. You can then iterate through the array, using the same switch function as above to ask the user the appropriately randomized question.

          Now... write it! 🙂

          • The Perplexed Programmer

            Thank you so much!!!
            Well thats way better than writing the code straight away, i'll learn a thing or two along the way!

  • Stratacos

    I am making a game where the computer generates a random number and the user tries to guess it. But the random number, which turned out to be 41, is the same every time I compile the program! How do I make it so that a new random number is selected each time the game is played? Here's the code for the random number generation functions:

    [code]

    bool isinrange(int x)
    {
    if(x<=100)
        return true;
    }

    unsigned int getnumber()
    {
    NewNumber:
        int x = rand();

        if (isinrange(x)==true)
            return x;
        else
            goto NewNumber;
    }

    • Alex

      1) Make sure you're calling srand() only once, at the top of main, and passing it the appropriate parameter.
      2) Call rand() once immediately afterward and discard the result.

      If you do those two things, you should get randomized numbers out of rand().

  • antiriad7

    Hi,

    Learning your tutorials one by one, I like it extremely, it's so easily explained, but it's a bit difficult for me to remember syntax and keywords, they are numerous. 😀

    I wonder how to use Mersenne Twister for given ranges, we can't use RAND_MAX like we did in another occasion. You said that when using modulus operator, numbers don't have same probability. How can I use Mersenne Twister for given ranges with equal probability for every possible number?

    Thank you in advance!

  • The Perplexed Programmer

    Hey there!
    In the following snippet,  why do we use

    and not

    if we want to print a new line after 5 numbers?

  • Astronoid

    Hello Alex,
    Thank you for doing your best in this tutorial; currently I'm facing a problem which is I'm trying to implement the function you mentioned above which give random number within a range; however, that program always print the same number every time I run which is 4 or 5; what is the problem here and thank you for your efforts.

  • Curiosity

    According to RECURRENCE relation relation used in LCG's :-
    the "multiplier" and the "increment" must be smaller than the "modulus",
    But in the 1st example of PRNG, the "multiplier" & the "increment" are greater than The "modulus"...
    Please TELL, WHY?

  • Curiosity

    You dint tell about setting a range through (rand() % upper_limit) + lower_limit, randomize()(which is easier than srand() as it internally implements a macro that calls the function time(), random() function and random(Upper_Limit) + Lower_Limit where,
    % and + are overloaded operators.

    • Alex

      randomize() isn't officially part of C++, and is only supported by some older compilers.

      (rand() % upper_limit) + lower_limit leads to an uneven distribution when RAND_MAX+1 isn't evenly divisible by upper_limit.

  • John

    When I compile and run the last example, i.e. in the section "Random numbers in C++11", I always get the same sequence of numbers. Is it correct to assume that no hardware entropy source is available, and the generator can not be initialized with a random seed?

    main.cpp

    Example

    Run 1:
    2412496532    3119216746    1495923606    3931352601    
    26313293    2552602825    3745457912    2213446826    
    4119067789    4188234190    728322180    2841381042

    Run 2:
    2412496532    3119216746    1495923606    3931352601    
    26313293    2552602825    3745457912    2213446826    
    4119067789    4188234190    728322180    2841381042

    • Alex

      Looks like maybe a compiler bug. See this.

      • John

        Thanks, my understanding is that not all functionalities specified in the c++11 standard have yet been implemented in GCC 6.3.0, and the switch -std=c++11 should bee seen as partly experimental. The recommendation for "std::random_device rd" is to use the boost library. The code then looks like this

        I'm probably getting a bit out of scope for this tutorial now, but is the correct way to look at the code

        1. random_device and mt19937 lives int the boost namespace? Basically because of the scope resolution operator ::  

        2. The function prototypes of boost::random_device and  boost::mt19937 are located in the header files

        The extension for these header files are .hpp, not .h, does that have any special meaning?

        3. The code for boost is compiled into object files, and these object files, libboost_random.a and libboost_system.a, needs to be include when compiling and linking, i.e.

        g++ -Wall -std=c++11 -pedantic-errors main.cpp libboost_random.a libboost_system.a

        The file extension is .a, not .o, is there any special reason for this?

        • Alex

          1) It looks like boost includes its own version of the random code. To differentiate the boost version from the C++ standard version, the boost version lives in the boost namespace, whereas the standard version lives in the std namespace.

          2) .hpp is an uncommon but sometimes used way of denoting that a header file belongs to C++ (whereas .h could be C or C++)

          3) These aren't object files -- they're precompiled boost library files that get linked into your code in the same way that the standard library gets linked into your code when you use its functionality. Just, in the case, because boost is a 3rd party library, you need to be explicit about wanting to link it.

  • Robbie Williams

    Hey Alex, loving these so far, you're an amazing teacher and you deserve a lifetime of gratitude =D. Just a quickie: I'm fairly bad at math, but I assumed that if you wanted to get a random number within a certain range you could just use remainder:

    Can you please explain why this is incorrect, as it seems to work as far as I have tested perfectly. Thankyou!!

    • Alex

      This almost works, but numbers at the low end of the range will show up more often than numbers at the high end of the range.

      Pretend your random number generator only generated numbers between 0 and 9. Now let's say you did a mod 4 to map that range to 0-3. Here's how it would map:
      0 = 0
      1 = 1
      2 = 2
      3 = 3
      4 = 0
      5 = 1
      6 = 2
      7 = 3
      8 = 0
      9 = 1

      As you can see, 0 and 1 came up three times, whereas 2 and 3 only came up twice. This can bias your result.

  • Advokat HadziTonic

    ..and how do you limit the random number range (dice problem) but using the Mersenne Twister ?

    • Alex

      You can use std::uniform_int_distribution on top of the Mersenne Twister:

  • Rohit

    Why is this code generating same number again and again?
    #include <iostream>
    #include <cstdlib>
    #include <ctime>

    int getRandomNumber(int min, int max)
    {
        static const double fraction = 1.0 / (static_cast<double>(RAND_MAX) + 1.0);  // static used for efficiency, so we only calculate this value once
        std::cout << "time:" << static_cast<int>(time(0)) << "\n";
        return static_cast<int>(rand() * fraction * (max - min + 1) + min);
    }

    int main()
    {
        srand(static_cast<unsigned int>(time(0)));

        std::cout << getRandomNumber(1, 6);
        return 0;
    }

    • Alex

      Call rand() once to discard the first result.

      • Rohit

        Didn't get you...Can u please tell to code reply with the correct edited code to make me understand the concept? I want the program to give me different number b/w 1 and 6 everytime when I run it.

        • Alex

  • Rohit

    please explain this statement [ static const double fraction = 1.0 / (static_cast<double>(RAND_MAX) + 1.0); ]
    Why this statement is used?
    I checked for the same thing on google but I got the all of them have directly returned [ return min + rand()*(max - min + 1) ] in their codes. Is there anything specific to use the fraction variable?

    • Alex

      "min + rand()*(max - min + 1)" only works if rand() returns a result between 0 and 1. Our rand() returns a number between 0 and RAND_MAX, so we use the fraction to compress that range down to a number between 0 and 1.

  • Rohit

    q1 - time(0), what does it mean?
    q2 - what will happen if write time(1) or time(2) or any other integer other than 0?

    • Alex

      0 is used as a null in this case, to indicate that no parameter is being passed in. Any other integer value will cause a compilation error.

  • Nguyen

    Hi Alex,

    #include <iostream>
    #include <cstdlib> // for rand() and srand()
    #include <ctime> // for time()

    int main()
    {
        srand(static_cast<unsigned int>(time(0))); // set initial seed value to system clock

        for (int count=0; count < 100; ++count)
        {
            std::cout << rand() << "\t";

            // If we've printed 5 numbers, start a new row
            if ((count+1) % 5 == 0)
                std::cout << "\n";
        }
    }

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

    It looks to me that this grogram will generate a different sequence of random numbers every time because we "refresh" or run the program all over again at a different time.  Is it right?  If it is right, then I have a question to your solution of a game of hi-lo.  My question is that why srand() should only be called once at the start of the program, it needs to be outside the loop?  I thought if it was inside of the loop (do-while), it would be "refreshed" or ran again at a different time.

    Thanks, Have a great day.

    • Alex

      Yes, this program generates different results because the random number generator seed is tied to the system clock, which is different every time we run the program.

      The results of the random number generator are only "sufficiently random" if you don't reset the random number generator seed while the program is running.

  • SadmanTariq

    why does this program always print the same number?

    p.s. I am using code::blocks and GNU GCC Compiler

    • Alex

      Probably because you're calling srand() inside of getRandomNumber(), which is resetting your random seed every time you call the function. You should only call srand() once at the start of your program (and then don't forget to call rand() once to discard the first result).

  • Rafael

    Hi Alex, I'm testing this random number generation with enums but I can't figure out why is it that the following code doesn't execute as expected and, after a few run-through, a pattern is observed:

    • Alex

      First, you're missing break statements after each case. This is causing your cases to fall through, leading to multiple print statements with each iteration.

      Second, you're getting the same results each time because you're recreating your std::default_random_engine every time you call randomNumberGenerator(). You can avoid this by making variable number static, so it's not recreated with every call.

  • Kayla

    Could you use a rounding function to spread rand() over the desired range? e.g.:

    • Alex

      Your program doesn't make any sense to me. But to your specific question, using round() isn't better than truncating and will probably cause additional problems (the numbers at the top end of your range will get rounded up to myMax, but nothing will get rounded down to myMax, so the occurrence of myMax will only be half that of the other numbers).

Leave a Comment

Put all code inside code tags: [code]your code here[/code]