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 forstd::mt19937
touint32_t
on x64, eventually this should be fixed and you can sayMyRNG::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
To_String Is Not a Member of Std, Says G++ (Mingw)
Is #Pragma Once a Safe Include Guard
Is There a Max Array Length Limit in C++
Embedding Resources in Executable Using Gcc
Does the Size of an Int Depend on the Compiler And/Or Processor
Why Is the Type of the Main Function in C and C++ Left to the User to Define
Do Built-In Types Have Default Constructors
What Does Casting to 'Void' Really Do
How to Determine If a String Is a Number With C++
Using Custom Std::Set Comparator
How Does Virtual Inheritance Solve the "Diamond" (Multiple Inheritance) Ambiguity
When Is the "Typename" Keyword Necessary
Array Placement-New Requires Unspecified Overhead in the Buffer