C++ random number generation

10,524

Solution 1

You're almost there! The rand() function returns a random value in a pretty large range (0 to RAND_MAX). The use of the modulus operator wraps this down into a smaller range (from 0 to 9, since you're modding by 10) and then the +1 moves this to be from 1 to 10.

To get values between 0 and 10, you can take rand and mod its value by 11:

r = rand() % 11;

More generally, to get random values in the range [0, n], you can write

r = rand() % (n + 1);

And finally, to get values in the range [k, n + k], you can write

r = rand() % (n + 1) + k;

Of course, as purists will point out, this isn't necessarily going to give you truly uniform values because modding rand() by some value will not distribute all the integers evenly. This usually isn't a problem (you'll be off by a very, very small amount), but if it is you may want to consider looking into a more robust random number generator than rand().

Solution 2

You leave out the +1 to start with 0. And since there are 11 different values you want, you need to calculate the remainder modulo 11 instead of 10.

r = rand() % 11;

Note that you need to seed a PRNG so it doesn't always produce the same sequence.

And the standard rand() function sucks. The quality of random numbers is very low, and not fit for many purposes. I strongly recommend using a better generator.

A Mersenne twister is a popular choice, and in one my projects I used Well512 since it's fast, good and easy to implement.

If the user must not predict the random numbers even those good PRNGs are not enough and you have to choose a cryptographic PRNG. They can neither be predicted (with realistic computational power) nor be distinguished from real random numbers unless you know the seed. They are a bit slower though.

Solution 3

Generating a uniform distribution is much simpler and less error prone in C++11 using std::uniform_real_distribution or for the integer case std::uniform_int_distribution. Here is a sample using std::uniform_real_distribution which displays a simple graphic to give a rough demonstration that it is uniform:

#include <iostream>
#include <iomanip>
#include <string>
#include <random>

int main()
{
    std::random_device rd;

    //
    // Engines 
    //
    std::mt19937 e2(rd());
    //std::knuth_b e2(rd());
    //std::default_random_engine e2(rd()) ;

    std::uniform_real_distribution<> dist(0, 10);

    const int nstars=95;     // maximum number of stars to distribute
    const int nintervals=10; // number of intervals

    int p[nintervals]={};

    for (int i=0; i<100000; ++i)
    {
      double number = dist(e2);
      ++p[int(number)];
    }

    std::cout << std::fixed; std::cout.precision(1);

    for (int i=0; i<nintervals; ++i)
    {
      std::cout << float(i) << "-" << std::setw(4) << float(i+1) << ": ";
      std::cout << std::string(p[i]*nstars/100000,'*') << std::endl;
    }

    return 0 ;
}

Sample result:

0.0- 1.0: *********
1.0- 2.0: *********
2.0- 3.0: *********
3.0- 4.0: *********
4.0- 5.0: *********
5.0- 6.0: *********
6.0- 7.0: *********
7.0- 8.0: *********
8.0- 9.0: *********
9.0-10.0: *********

Some of the sample code was taken from this reference.

Share:
10,524
Simplicity
Author by

Simplicity

Updated on June 09, 2022

Comments

  • Simplicity
    Simplicity over 1 year

    For example, the following expression:

    r = (rand() % 10)+1;

    Generates a random number from 1-10.

    How can we make it generate random numbers from 0-10?

    Thanks.