aboutsummaryrefslogtreecommitdiffstats
path: root/util/random/common_ops.h
blob: 0bbb80f3d3e41998025a95be240ab277cfcf8539 (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
126
127
128
129
130
#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;
    }
} // namespace NPrivate

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