#pragma once #include "lcg_engine.h" #include "common_ops.h" #include #include // based on http://www.pcg-random.org/. See T*FastRng* family below. struct TPCGMixer { static inline ui32 Mix(ui64 x) noexcept { const ui32 xorshifted = ((x >> 18u) ^ x) >> 27u; const ui32 rot = x >> 59u; return RotateBitsRight(xorshifted, rot); } }; using TFastRng32Base = TLcgRngBase, TPCGMixer>; using TReallyFastRng32Base = TLcgRngBase, TPCGMixer>; class IInputStream; struct TFastRng32: public TCommonRNG, public TFastRng32Base { inline TFastRng32(ui64 seed, ui32 seq) : TFastRng32Base(seed, seq) { } TFastRng32(IInputStream& entropy); }; // faster than TFastRng32, but have only one possible stream sequence struct TReallyFastRng32: public TCommonRNG, public TReallyFastRng32Base { inline TReallyFastRng32(ui64 seed) : TReallyFastRng32Base(seed) { } TReallyFastRng32(IInputStream& entropy); }; class TFastRng64: public TCommonRNG { public: struct TArgs { TArgs(ui64 seed) noexcept; TArgs(IInputStream& entropy); ui64 Seed1; ui64 Seed2; ui32 Seq1; ui32 Seq2; }; TFastRng64(ui64 seed1, ui32 seq1, ui64 seed2, ui32 seq2) noexcept; /* * simplify constructions like * TFastRng64 rng(17); * TFastRng64 rng(Seek()); //from any IInputStream */ inline TFastRng64(const TArgs& args) noexcept : TFastRng64(args.Seed1, args.Seq1, args.Seed2, args.Seq2) { } inline ui64 GenRand() noexcept { const ui64 x = R1_.GenRand(); const ui64 y = R2_.GenRand(); return (x << 32) | y; } inline void Advance(ui64 delta) noexcept { R1_.Advance(delta); R2_.Advance(delta); } private: TFastRng32Base R1_; TFastRng32Base R2_; }; namespace NPrivate { template struct TFastRngTraits; template <> struct TFastRngTraits { using TResult = TReallyFastRng32; }; template <> struct TFastRngTraits { using TResult = TFastRng64; }; } template using TFastRng = typename ::NPrivate::TFastRngTraits::TResult;