#pragma once
#include <util/system/defaults.h>
#include <util/system/yassert.h>
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 <class T>
static inline ui64 ToRand64(T&& rng, ui32 x) noexcept {
return ((ui64)x) | (((ui64)rng.GenRand()) << 32);
}
template <class T>
static constexpr ui64 ToRand64(T&&, ui64 x) noexcept {
return x;
}
/*
* return value in range [0, max) from any generator
*/
template <class T, class TRandGen>
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 <class TRandType, class T>
struct TCommonRNG {
using TResult = TRandType;
using result_type = TRandType;
inline T& Engine() noexcept {
return static_cast<T&>(*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();
}
};