aboutsummaryrefslogtreecommitdiffstats
path: root/util/random/random.cpp
blob: 561f8aa4124fd17fb7349e4a0d36e703b49e295b (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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#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);
}