aboutsummaryrefslogtreecommitdiffstats
path: root/util/random/random.cpp
blob: c2775ec3f02a02f054566edff104756e2ba3d927 (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;
    };
} // namespace

#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);
}