10

Is there a function for obtaining uniformly distributed pseudo-random integers in some specified range? I could write my own function using rand, but this seems like a common enough situation that there's probably something in the STL for it.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Andreas
  • 7,470
  • 10
  • 51
  • 73

3 Answers3

16

Boost provides many tools for random number generation. For uniform distributions you have this one:

http://www.boost.org/doc/libs/1_49_0/doc/html/boost/random/uniform_real_distribution.html

EDIT: updated to include the new C++11 implementation. For the case of integers, here you have the reference:

http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution

A simple example would be:

#include <random>
#include <iostream>
int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(1, 6);
    for(int n=0; n<10; ++n)
        std::cout << dis(gen) << ' ';
    std::cout << '\n';
}
betabandido
  • 18,946
  • 11
  • 62
  • 76
10

To generate pseudo-random numbers in C++, a very good option is using the Mersenne twister pseudo-random number generator engine: std::mt19937 from the <random> header.

We can think of this engine as a black-box that spits out high-quality random bits.

Then, these random bits can be shaped in some integers output using a distribution; in particular, to get uniformly distributed pseudo-random numbers, a std::uniform_int_distribution can be used.

Note that the engine object must be initialized with a seed.
std::random_device can be used for that purpose.

So, this process can be summarized in three logical steps:

  1. Create an instance of std::random_device, to get a non-deterministic seed for the Mersenne twister engine.
  2. Create an instance of std::mt19937 engine, to get high-quality pseudo-random bits.
  3. Use a std::uniform_int_distribution to shape these random bits in uniformly-distributed integers.

Compilable C++ code follows:

#include <iostream>     // for console output
#include <random>       // for pseudo-random number generators and distributions

int main()
{
    // Use random_device to generate a seed for Mersenne twister engine.
    std::random_device rd;    

    // Use Mersenne twister engine to generate pseudo-random numbers.
    std::mt19937 engine(rd());
    
    // "Filter" MT engine's output to generate pseudo-random integer values,
    // **uniformly distributed** on the closed interval [0, 99].  
    // (Note that the range is [inclusive, inclusive].)
    std::uniform_int_distribution<int> dist(0, 99);

    // Generate and print 10 pseudo-random integers
    for (int i = 0; i < 10; ++i)
    {
        std::cout << dist(engine) << ' ';
    }
    std::cout << std::endl;
}

For more details on generating pseudo-random numbers in C++ (including reasons why rand() is not good), see this video by Stephan T. Lavavej (from Going Native 2013):

rand() Considered Harmful

Community
  • 1
  • 1
Mr.C64
  • 41,637
  • 14
  • 86
  • 162
  • +1 It sure took a while but this was finally merged. You may want to edit your question to indicate that it was part of a merge and a comment to the OP as well so they understand why this new answer popped up with an old date. – Shafik Yaghmour Apr 16 '14 at 12:52
  • I don't know why everyone say that Mersenne Twister is so great and "high-quality". It's not. It is complicated, has an enormous memory footprint and still fails multiple tests of the TestU01 BigCrush test suite. There are several simpler, faster and much higher quality PRNGs today with adequate periods. – plasmacel Aug 08 '16 at 13:50
  • @plasmacel: I asked Stephan T. Lavavej (VC STL maintainer) and he confirmed its the best standard PRNG. What would you propose as better alternatives? – Mr.C64 Aug 08 '16 at 20:46
0

To generate one or specified number of random variables with uniform distribution on integer domain using std::generate_n and boost:

#include <iostream>
#include <algorithm>
#include <boost/random.hpp>

/*
 * 
 */
int main(int argc, char** argv) {
    boost::mt19937 rand_generator(std::time(NULL));
    boost::random::uniform_int_distribution<> int_distribution(0, 100);

    //Need to pass generator
    std::cout << int_distribution(rand_generator) << std::endl;

    //Associate generator with distribution
    boost::random::variate_generator<boost::mt19937&,
            boost::random::uniform_int_distribution<>
            > int_variate_generator(rand_generator, int_distribution);

    //No longer need to pass generator
    std::cout << int_variate_generator() << std::endl;
    std::generate_n( std::ostream_iterator<int>(std::cout, ","), 3, int_variate_generator);
    return 0;
}
4pie0
  • 29,204
  • 9
  • 82
  • 118