random: use more robust seeding strategy

This commit is contained in:
Danny Robson 2018-05-30 14:32:39 +10:00
parent cdac2dcbc2
commit a90ce0920f

View File

@ -18,18 +18,49 @@
#define CRUFT_UTIL_RANDOM_HPP #define CRUFT_UTIL_RANDOM_HPP
#include <algorithm> #include <algorithm>
#include <array>
#include <random> #include <random>
#include <limits> #include <limits>
namespace util::random { namespace util::random {
template <typename T>
struct state_size;
template <
class UIntType,
size_t w, size_t n, size_t m, size_t r,
UIntType a, size_t u, UIntType d, size_t s,
UIntType b, size_t t,
UIntType c, size_t l, UIntType f
> struct state_size<std::mersenne_twister_engine<UIntType,w,n,m,r,a,u,d,s,b,t,c,l,f>> {
static constexpr auto value = n * sizeof (UIntType);
};
template <typename UIntType, UIntType a, UIntType c, UIntType m>
struct state_size<std::linear_congruential_engine<UIntType,a,c,m>> {
static constexpr auto value = sizeof (UIntType);
};
template <typename T>
constexpr auto state_size_v = state_size<T>::value;
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
/// return correctly initialised thread-local generator of an unspecified, /// return correctly initialised thread-local generator of an unspecified,
/// but not entirely useless, type. ie, not LCG. /// but not entirely useless, type. ie, not LCG.
inline auto& inline auto&
generator (void) generator (void)
{ {
static thread_local std::default_random_engine gen { std::random_device {}() }; using generator_t = std::default_random_engine;
static thread_local generator_t gen = [] () {
std::array<int,state_size_v<generator_t> / 4> seed;
std::generate (seed.begin (), seed.end (), std::random_device ());
std::seed_seq seq (seed.begin (), seed.end ());
return generator_t (seq);
} ();
return gen; return gen;
} }