aboutsummaryrefslogtreecommitdiffstats
path: root/util/random/fast.h
blob: 69b1772dd859b6f9e44574f4c23881e23a30f0f9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#pragma once 
 
#include "lcg_engine.h" 
#include "common_ops.h" 
 
#include <util/generic/bitops.h>
#include <util/system/platform.h> 
 
// 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<TLcgIterator<ui64, ULL(6364136223846793005)>, TPCGMixer>; 
using TReallyFastRng32Base = TLcgRngBase<TFastLcgIterator<ui64, ULL(6364136223846793005), ULL(1)>, TPCGMixer>; 
 
class IInputStream;
 
struct TFastRng32: public TCommonRNG<ui32, TFastRng32>, 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<ui32, TReallyFastRng32>, public TReallyFastRng32Base { 
    inline TReallyFastRng32(ui64 seed) 
        : TReallyFastRng32Base(seed) 
    { 
    } 
 
    TReallyFastRng32(IInputStream& entropy);
}; 
 
class TFastRng64: public TCommonRNG<ui64, TFastRng64> { 
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 <typename T> 
    struct TFastRngTraits; 
 
    template <> 
    struct TFastRngTraits<ui32> { 
        using TResult = TReallyFastRng32; 
    }; 
 
    template <> 
    struct TFastRngTraits<ui64> { 
        using TResult = TFastRng64; 
    }; 
} 
 
template <typename T> 
using TFastRng = typename ::NPrivate::TFastRngTraits<T>::TResult;