#include "random.h" #include "entropy.h" #include "mersenne.h" #include <util/system/getpid.h> #include <util/thread/singleton.h> #include <util/stream/multi.h> #include <util/stream/mem.h> #include <util/digest/numeric.h> namespace { struct TProcStream { ui32 Extra; TMemoryInput MI; TMultiInput TI; static inline ui32 ExtraData() noexcept { ui32 data; EntropyPool().LoadOrFail(&data, sizeof(data)); return IntHash(data ^ GetPID()); } inline TProcStream() noexcept : Extra(ExtraData()) , MI(&Extra, sizeof(Extra)) , TI(&MI, &EntropyPool()) { } inline IInputStream& S() noexcept { return TI; } }; template <class T> struct TRndGen: public TMersenne<T> { inline TRndGen() : TMersenne<T>(TProcStream().S()) { } inline TRndGen(T seed) : TMersenne<T>(seed) { } }; template <class T> static inline TRndGen<T>* GetRndGen() { return FastTlsSingletonWithPriority<TRndGen<T>, 2>(); } template <unsigned N> struct TToRealTypeBySize { using TResult = ui32; }; template <> struct TToRealTypeBySize<8> { using TResult = ui64; }; template <class T> struct TToRealType { using TResult = typename TToRealTypeBySize<sizeof(T)>::TResult; }; } #define DEF_RND(TY) \ template <> \ TY RandomNumber<TY>() { \ return GetRndGen<TToRealType<TY>::TResult>()->GenRand(); \ } \ \ template <> \ TY RandomNumber<TY>(TY n) { \ return GetRndGen<TToRealType<TY>::TResult>()->Uniform(n); \ } DEF_RND(char) DEF_RND(unsigned char) DEF_RND(unsigned int) DEF_RND(unsigned long) DEF_RND(unsigned short) DEF_RND(unsigned long long) #undef DEF_RND template <> bool RandomNumber<bool>() { return RandomNumber<ui8>() % 2 == 0; } template <> float RandomNumber<float>() { float ret; do { ret = (float)GetRndGen<ui64>()->GenRandReal2(); } while (ret >= 1); return ret; } template <> double RandomNumber<double>() { return GetRndGen<ui64>()->GenRandReal4(); } template <> long double RandomNumber<long double>() { return RandomNumber<double>(); } void ResetRandomState() { *GetRndGen<ui32>() = TRndGen<ui32>(); *GetRndGen<ui64>() = TRndGen<ui64>(); } void SetRandomSeed(int seed) { *GetRndGen<ui32>() = TRndGen<ui32>(seed); *GetRndGen<ui64>() = TRndGen<ui64>(seed); }