C++11 Random Numbers

Generate random numbers using C++11 random library

Stephan T. Lavavej(stl) from Microsoft did a talk at Going Native about how to use the new C++11 random functions and why not to use rand(). In it, he included a slide that basically solves your question. I've copied the code from that slide below.

You can see his full talk here:

#include <random>
#include <iostream>

int main() {
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_real_distribution<double> dist(1.0, 10.0);

for (int i=0; i<16; ++i)
std::cout << dist(mt) << "\n";
}

We use random_device once to seed the random number generator named mt. random_device() is slower than mt19937, but it does not need to be seeded because it requests random data from your operating system (which will source from various locations, like RdRand for example).


Looking at this question / answer, it appears that uniform_real_distribution returns a number in the range [a, b), where you want [a, b]. To do that, our uniform_real_distibution should actually look like:

std::uniform_real_distribution<double> dist(1, std::nextafter(10, DBL_MAX));

How to Understand C++11 random number generator

random_device is slow but genuinely random, it's used to generate the 'seed' for the random number sequence.

mt19937 is fast but only 'pseudo random'. It needs a 'seed' to start generating a sequence of numbers. That seed can be random (as in your example) so you get a different sequence of random numbers each time. But it could be a constant, so you get the same sequence of numbers each time.

uniform_int_distribution is a way of mapping random numbers (which could have any values) to the numbers you're actually interested in, in this case a uniform distribution of integers from 1 to 6.

As is often the case with OO programming, this code is about division of responsibilities. Each class contributes a small piece to the overall requirement (the generation of dice rolls). If you wanted to do something different it's easy because you've got all the pieces in front of you.

If this is too much then all you need to do is write a function to capture the overall effect, for instance

int dice_roll()
{
static std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_int_distribution<> dis(1, 6);
return dis(gen);
}

dis is an example of a function object or functor. It's an object which overloads operator() so it can be called as if it was a function.

Random number generation in C++11: how to generate, how does it work?

The question is way too broad for a complete answer, but let me cherry-pick a couple of interesting points:

Why "equally likely"

Suppose you have a simple random number generator that generate the numbers 0, 1, ..., 10 each with equal probability (think of this as the classic rand()). Now you want a random number in the range 0, 1, 2, each with equal probability. Your knee-jerk reaction would be to take rand() % 3. But wait, the remainders 0 and 1 occur more often than the remainder 2, so this isn't correct!

This is why we need proper distributions, which take a source of uniform random integers and turn them into our desired distribution, like Uniform[0,2] in the example. Best to leave this to a good library!

Engines

Thus at the heart of all randomness is a good pseudo-random number generator that generates a sequence of numbers that uniformly distributed over a certain interval, and which ideally have a very long period. The standard implementation of rand() isn't often the best, and thus it's good to have a choice. Linear-congruential and the Mersenne twister are two good choices (LG is actually often used by rand(), too); again, it's good to let the library handle that.

How it works

Easy: first, set up an engine and seed it. The seed fully determines the entire sequence of "random" numbers, so a) use a different one (e.g. taken from /dev/urandom) each time, and b) store the seed if you wish to recreate a sequence of random choices.

#include <random>

typedef std::mt19937 MyRNG; // the Mersenne Twister with a popular choice of parameters
uint32_t seed_val; // populate somehow

MyRNG rng; // e.g. keep one global instance (per thread)

void initialize()
{
rng.seed(seed_val);
}

Now we can create distributions:

std::uniform_int_distribution<uint32_t> uint_dist;         // by default range [0, MAX]
std::uniform_int_distribution<uint32_t> uint_dist10(0,10); // range [0,10]
std::normal_distribution<double> normal_dist(mean, stddeviation); // N(mean, stddeviation)

...And use the engine to create random numbers!

while (true)
{
std::cout << uint_dist(rng) << " "
<< uint_dist10(rng) << " "
<< normal_dist(rng) << std::endl;

}

Concurrency

One more important reason to prefer <random> over the traditional rand() is that it is now very clear and obvious how to make random number generation threadsafe: Either provide each thread with its own, thread-local engine, seeded on a thread-local seed, or synchronize access to the engine object.

Misc

  • An interesting article on TR1 random on codeguru.
  • Wikipedia has a good summary (thanks, @Justin).
  • In principle, each engine should typedef a result_type, which is the correct integral type to use for the seed. I think I had a buggy implementation once which forced me to force the seed for std::mt19937 to uint32_t on x64, eventually this should be fixed and you can say MyRNG::result_type seed_val and thus make the engine very easily replaceable.

C++11 random numbers

This is how to use the C++11 random number generation for this purpose (adjusted from http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution):

#include <random>
#include <iostream>
int main()
{
/* Initialise. Do this once (not for every
random number). */
std::random_device rd;
std::mt19937_64 gen(rd());

/* This is where you define the number generator for unsigned long long: */
std::uniform_int_distribution<unsigned long long> dis;

/* A few random numbers: */
for (int n=0; n<10; ++n)
std::cout << dis(gen) << ' ';
std::cout << std::endl;
return 0;
}

Instead of unsigned long long, you could use std::uintmax_t from cstdint to get the largest possible integer range (without using an actual big-integer library).

Generate random numbers in C++-11 in different parts of a code using the same seed

Since you want to use the same engine, you have to use the same engine. (That much is a singleton.) Pass a reference to RNG, store and use a reference within RNG. Minor changes to your code make this so (one of the comments already pointed this out):

ENG ŋ
RNG(ENG &eng_, int imin, int imax)
: idist(imin, imax), eng(eng_) {}

void myfunc(ENG &eng_, int imin, int imax, int N)

But I like it better if the engine is hidden in RNG like this:

class RNG {
private:
static ENG eng;
iDIST idist;
public:
static void seed(int s) { eng.seed(s); }
RNG(int imin, int imax) : idist(imin, imax) {}
int generate() { return idist(eng); }
};

// the one generator, stored as RNG::eng
ENG RNG::eng;

// print some generated numbers from a range
void printRandomNumbers(int imin, int imax, int N){
std::cout << "Range = [" << imin << "," << imax << "]" << std::endl;
RNG myirn(imin, imax);
for (int i = 0; i < N; i++){
std::cout << myirn.generate() << std::endl;
}
return;
}

int main()
{
//Seed globally
int myseed = 1;
RNG::seed(myseed);
printRandomNumbers(1, 10, 5);
printRandomNumbers(11, 20, 5);
printRandomNumbers(21, 30, 5);
return 0;
}

C++ 11 random number generation not working

The issue here is that std::random_device does not have to really be a random device. It can be a wrapper around an unseeded rand which would give you the same value every time you use it. This means your seed for engine would be the same which means the pseudo-random sequence it generates would be the same as well.

One way you could get around this is to use the current as a seed like

auto seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 engine {seed};

But this can be manipulated via external processes and isn't very fined grained so multiple instances seeded at the same time could all make the same sequence.

Random numbers in C++11: is there a simple way to seed the generator in one place of the code, then use it in different functions?

Do you think I will have to pass the seeded engine from main() to UseSomeRandomness() in LibraryA, then from UseSomeRandomness() to GetRandDoubleBetween0And1() in LibraryB?

Yes.

You instantiate the generator once, then pass a reference or pointer to it into whatever contexts want to use it.

This is just like dealing with any other resource.

Efficient random number generation with C++11 random

One thing you can do is to have a permanent distribution object so that you only create the param_type object each time like this:

template<typename Integral>
Integral randint(Integral min, Integral max)
{
using param_type =
typename std::uniform_int_distribution<Integral>::param_type;

// only create these once (per thread)
thread_local static std::mt19937 eng {std::random_device{}()};
thread_local static std::uniform_int_distribution<Integral> dist;

// presumably a param_type is cheaper than a uniform_int_distribution
return dist(eng, param_type{min, max});
}


Related Topics



Leave a reply



Submit