#pragma once #include #include namespace NPrivate { constexpr double ToRandReal1(const ui32 x) noexcept { return x * (double)(1.0 / 4294967295.0); } constexpr double ToRandReal2(const ui32 x) noexcept { return x * (double)(1.0 / 4294967296.0); } constexpr double ToRandReal3(const ui32 x) noexcept { return ((double)x + 0.5) * (double)(1.0 / 4294967296.0); } constexpr double ToRandReal1(const ui64 x) noexcept { return (x >> 11) * (double)(1.0 / 9007199254740991.0); } constexpr double ToRandReal2(const ui64 x) noexcept { return (x >> 11) * (double)(1.0 / 9007199254740992.0); } constexpr double ToRandReal3(const ui64 x) noexcept { return ((x >> 12) + 0.5) * (double)(1.0 / 4503599627370496.0); } constexpr double ToRandReal4(const ui64 x) noexcept { return double(x * (double)(1.0 / 18446744073709551616.0L)); } template static inline ui64 ToRand64(T&& rng, ui32 x) noexcept { return ((ui64)x) | (((ui64)rng.GenRand()) << 32); } template static constexpr ui64 ToRand64(T&&, ui64 x) noexcept { return x; } /* * return value in range [0, max) from any generator */ template static T GenUniform(T max, TRandGen&& gen) { Y_ABORT_UNLESS(max > 0, "Invalid random number range [0, 0)"); const T randmax = gen.RandMax() - gen.RandMax() % max; T rand; while ((rand = gen.GenRand()) >= randmax) { /* no-op */ } return rand % max; } } template struct TCommonRNG { using TResult = TRandType; using result_type = TRandType; inline T& Engine() noexcept { return static_cast(*this); } static constexpr TResult _Min = TResult(0); static constexpr TResult _Max = TResult(-1); static constexpr TResult RandMax() noexcept { return _Max; } static constexpr TResult RandMin() noexcept { return _Min; } /* generates uniformly distributed random number on [0, t) interval */ inline TResult Uniform(TResult t) noexcept { return ::NPrivate::GenUniform(t, Engine()); } /* generates uniformly distributed random number on [f, t) interval */ inline TResult Uniform(TResult f, TResult t) noexcept { return f + Uniform(t - f); } /* generates 64-bit random number for current(may be 32 bit) rng */ inline ui64 GenRand64() noexcept { return ::NPrivate::ToRand64(Engine(), Engine().GenRand()); } /* generates a random number on [0, 1]-real-interval */ inline double GenRandReal1() noexcept { return ::NPrivate::ToRandReal1(Engine().GenRand()); } /* generates a random number on [0, 1)-real-interval */ inline double GenRandReal2() noexcept { return ::NPrivate::ToRandReal2(Engine().GenRand()); } /* generates a random number on (0, 1)-real-interval */ inline double GenRandReal3() noexcept { return ::NPrivate::ToRandReal3(Engine().GenRand()); } /* generates a random number on [0, 1) with 53-bit resolution */ inline double GenRandReal4() noexcept { return ::NPrivate::ToRandReal4(Engine().GenRand64()); } // compatibility stuff inline TResult operator()() noexcept { return Engine().GenRand(); } static constexpr TResult max() noexcept { return T::RandMax(); } static constexpr TResult min() noexcept { return T::RandMin(); } };