I'm looking for a set of portable distributions for the standard C++11 engines like `std::mt19937' (see http://en.cppreference.com/w/cpp/numeric/random).
The engine implementations perform consistently (i.e. same sequence generated on different platforms – tested with Clang and MSVC), but the distributions seem to be implemented differently on the different platforms.
So, even though the engines produce the same sequence, it seems that a distribution (for example, std::normal_distribution<double>
) does not use the same number of samples (i.e. produces different results) on the different platforms, which is not acceptable in my case.
Is there maybe a 3rd party lib I can use that follows the C++11 random templates, but that will deliver consistent values across popular platforms (Looking at support across GCC, MSVC and Clang/llvm).
Options I have looked at so far are:
- Boost.random (a bit heavy, but worthwhile since it matches the c++11 counterparts quite well)
- Cloning from libstd++ (also worthwhile and probably portable, but pulling out specific functions might not be straightforward)
- Creating my own C++11-like random distributions
I need uniform, normal, poison and Rayleigh.
I have created my own C++11 distributions:
template <typename T>
class UniformRealDistribution
{
public:
typedef T result_type;
public:
UniformRealDistribution(T _a = 0.0, T _b = 1.0)
:m_a(_a),
m_b(_b)
{}
void reset() {}
template <class Generator>
T operator()(Generator &_g)
{
double dScale = (m_b - m_a) / ((T)(_g.max() - _g.min()) + (T)1);
return (_g() - _g.min()) * dScale + m_a;
}
T a() const {return m_a;}
T b() const {return m_b;}
protected:
T m_a;
T m_b;
};
template <typename T>
class NormalDistribution
{
public:
typedef T result_type;
public:
NormalDistribution(T _mean = 0.0, T _stddev = 1.0)
:m_mean(_mean),
m_stddev(_stddev)
{}
void reset()
{
m_distU1.reset();
}
template <class Generator>
T operator()(Generator &_g)
{
// Use Box-Muller algorithm
const double pi = 3.14159265358979323846264338327950288419716939937511;
double u1 = m_distU1(_g);
double u2 = m_distU1(_g);
double r = sqrt(-2.0 * log(u1));
return m_mean + m_stddev * r * sin(2.0 * pi * u2);
}
T mean() const {return m_mean;}
T stddev() const {return m_stddev;}
protected:
T m_mean;
T m_stddev;
UniformRealDistribution<T> m_distU1;
};
The uniform distribution seems to deliver good results and the normal distribution delivers very good results:
100000 values -> 68.159% within 1 sigma; 95.437% within 2 sigma; 99.747% within 3 sigma
The normal distribution uses the Box-Muller method, which according to what I have read so far, is not the fastest method, but it runs more that fast enough for my application.
Both the uniform and normal distributions should work with any C++11 engine (tested with std::mt19937) and provides the same sequence on all platforms, which is exactly what I wanted.