Generate Random Numbers Using C++11 Random Library

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));

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).

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});
}

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;
}

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.

generating random array in c++11

First of all, you're doing more work than you need to with your Python version, just use:

np.random.uniform(lower_bound, upper_bound, size=(num_particle, dim))

In your C++ attempt, the line

std::generate(pos.begin(),pos.end(),distribution(generator));

Is incorrect as the third argument must be a function not a value. A reasonable C++ equivalent would be:

using RandomVector = std::vector<double>;
using RandomMatrix = std::vector<RandomVector>;

template <typename Generator=std::mt19937_64>
RandomMatrix&
fill_uniform(const double low, const double high, RandomMatrix& result)
{
Generator gen {static_cast<typename Generator::result_type>(time(0))};
std::uniform_real_distribution<double> dist {low, high};
for (auto& col : result) {
std::generate(std::begin(col), std::end(col), [&] () { return dist(gen); });
}
return result;
}

template <typename Generator=std::mt19937_64>
RandomMatrix
generate_uniform(const double low, const double high,
const std::size_t ncols, const std::size_t nrows)
{
RandomMatrix result(ncols, RandomVector(nrows));
return fill_uniform<Generator>(low, high, result);
}

int main()
{
auto m = generate_uniform(2, 11, 2, 3);
for (const auto& col : m) {
for (const auto& v : col) {
std::cout << v << " ";
}
std::cout << '\n';
}
}

You could generalise this to generate arbitrary dimension tensors (like the NumPy version) without too much work.

Is random number generation in multiple threads using C++11 random library slow just like using rand() in multiple threads?

Yes and no. Most of the C++11 random number generators are objects that encapsulate their own state, so as long as you create a separate generator object for each thread, each should be able to operate independently of the others (so you don't need any locking).

The specific case of std::random_device is a little different though: this is intended (but not guaranteed) to obtain truly non-deterministic data from some sort of random number generation hardware. The driver for that device may well impose locking requirements of its own -- and it's often fairly low bandwidth as well, so if you want to obtain a lot of numbers quickly, it's usually a poor choice.

In a typical case, you want to use one generator (other than std::random_device) per thread, and use std::random_device only to provide the initial seeds for those other generators. This may impose locks during that initialization, but then allows each thread to generate its random numbers without any interlock with other threads.



Related Topics



Leave a reply



Submit