xref: /freebsd/contrib/bc/include/rand.h (revision 10328f8b112381e25e324688c8603caf4cee94ac)
1252884aeSStefan Eßer /*
2252884aeSStefan Eßer  * *****************************************************************************
3252884aeSStefan Eßer  *
4252884aeSStefan Eßer  * Parts of this code are adapted from the following:
5252884aeSStefan Eßer  *
6252884aeSStefan Eßer  * PCG, A Family of Better Random Number Generators.
7252884aeSStefan Eßer  *
8252884aeSStefan Eßer  * You can find the original source code at:
9252884aeSStefan Eßer  *   https://github.com/imneme/pcg-c
10252884aeSStefan Eßer  *
11252884aeSStefan Eßer  * -----------------------------------------------------------------------------
12252884aeSStefan Eßer  *
13*10328f8bSStefan Eßer  * This code is under the following license:
14252884aeSStefan Eßer  *
15252884aeSStefan Eßer  * Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors
16*10328f8bSStefan Eßer  * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
17252884aeSStefan Eßer  *
18252884aeSStefan Eßer  * Permission is hereby granted, free of charge, to any person obtaining a copy
19252884aeSStefan Eßer  * of this software and associated documentation files (the "Software"), to deal
20252884aeSStefan Eßer  * in the Software without restriction, including without limitation the rights
21252884aeSStefan Eßer  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22252884aeSStefan Eßer  * copies of the Software, and to permit persons to whom the Software is
23252884aeSStefan Eßer  * furnished to do so, subject to the following conditions:
24252884aeSStefan Eßer  *
25252884aeSStefan Eßer  * The above copyright notice and this permission notice shall be included in
26252884aeSStefan Eßer  * all copies or substantial portions of the Software.
27252884aeSStefan Eßer  *
28252884aeSStefan Eßer  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29252884aeSStefan Eßer  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30252884aeSStefan Eßer  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31252884aeSStefan Eßer  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32252884aeSStefan Eßer  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33252884aeSStefan Eßer  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34252884aeSStefan Eßer  * SOFTWARE.
35252884aeSStefan Eßer  *
36252884aeSStefan Eßer  * *****************************************************************************
37252884aeSStefan Eßer  *
38252884aeSStefan Eßer  * Definitions for the RNG.
39252884aeSStefan Eßer  *
40252884aeSStefan Eßer  */
41252884aeSStefan Eßer 
42252884aeSStefan Eßer #ifndef BC_RAND_H
43252884aeSStefan Eßer #define BC_RAND_H
44252884aeSStefan Eßer 
45252884aeSStefan Eßer #include <stdint.h>
46252884aeSStefan Eßer #include <inttypes.h>
47252884aeSStefan Eßer 
48252884aeSStefan Eßer #include <vector.h>
49252884aeSStefan Eßer #include <num.h>
50252884aeSStefan Eßer 
513aa99676SStefan Eßer #if BC_ENABLE_EXTRA_MATH
523aa99676SStefan Eßer 
533aa99676SStefan Eßer #if BC_ENABLE_RAND
543aa99676SStefan Eßer 
55252884aeSStefan Eßer typedef ulong (*BcRandUlong)(void*);
56252884aeSStefan Eßer 
57252884aeSStefan Eßer #if BC_LONG_BIT >= 64
58252884aeSStefan Eßer 
59252884aeSStefan Eßer #ifdef BC_RAND_BUILTIN
60252884aeSStefan Eßer #if BC_RAND_BUILTIN
61252884aeSStefan Eßer #ifndef __SIZEOF_INT128__
62252884aeSStefan Eßer #undef BC_RAND_BUILTIN
63252884aeSStefan Eßer #define BC_RAND_BUILTIN (0)
64252884aeSStefan Eßer #endif // __SIZEOF_INT128__
65252884aeSStefan Eßer #endif // BC_RAND_BUILTIN
66252884aeSStefan Eßer #endif // BC_RAND_BUILTIN
67252884aeSStefan Eßer 
68252884aeSStefan Eßer #ifndef BC_RAND_BUILTIN
69252884aeSStefan Eßer #ifdef __SIZEOF_INT128__
70252884aeSStefan Eßer #define BC_RAND_BUILTIN (1)
71252884aeSStefan Eßer #else // __SIZEOF_INT128__
72252884aeSStefan Eßer #define BC_RAND_BUILTIN (0)
73252884aeSStefan Eßer #endif // __SIZEOF_INT128__
74252884aeSStefan Eßer #endif // BC_RAND_BUILTIN
75252884aeSStefan Eßer 
76252884aeSStefan Eßer typedef uint64_t BcRand;
77252884aeSStefan Eßer 
78252884aeSStefan Eßer #define BC_RAND_ROTC (63)
79252884aeSStefan Eßer 
80252884aeSStefan Eßer #if BC_RAND_BUILTIN
81252884aeSStefan Eßer 
82252884aeSStefan Eßer typedef __uint128_t BcRandState;
83252884aeSStefan Eßer 
84252884aeSStefan Eßer #define bc_rand_mul(a, b) (((BcRandState) (a)) * ((BcRandState) (b)))
85252884aeSStefan Eßer #define bc_rand_add(a, b) (((BcRandState) (a)) + ((BcRandState) (b)))
86252884aeSStefan Eßer 
87252884aeSStefan Eßer #define bc_rand_mul2(a, b) (((BcRandState) (a)) * ((BcRandState) (b)))
88252884aeSStefan Eßer #define bc_rand_add2(a, b) (((BcRandState) (a)) + ((BcRandState) (b)))
89252884aeSStefan Eßer 
90252884aeSStefan Eßer #define BC_RAND_NOTMODIFIED(r) (((r)->inc & 1UL) == 0)
91252884aeSStefan Eßer #define BC_RAND_ZERO(r) (!(r)->state)
92252884aeSStefan Eßer 
93252884aeSStefan Eßer #define BC_RAND_CONSTANT(h, l) ((((BcRandState) (h)) << 64) + (BcRandState) (l))
94252884aeSStefan Eßer 
95252884aeSStefan Eßer #define BC_RAND_TRUNC(s) ((uint64_t) (s))
96252884aeSStefan Eßer #define BC_RAND_CHOP(s) ((uint64_t) ((s) >> 64UL))
97252884aeSStefan Eßer #define BC_RAND_ROTAMT(s) ((unsigned int) ((s) >> 122UL))
98252884aeSStefan Eßer 
99252884aeSStefan Eßer #else // BC_RAND_BUILTIN
100252884aeSStefan Eßer 
101252884aeSStefan Eßer typedef struct BcRandState {
102252884aeSStefan Eßer 
103252884aeSStefan Eßer 	uint_fast64_t lo;
104252884aeSStefan Eßer 	uint_fast64_t hi;
105252884aeSStefan Eßer 
106252884aeSStefan Eßer } BcRandState;
107252884aeSStefan Eßer 
108252884aeSStefan Eßer #define bc_rand_mul(a, b) (bc_rand_multiply((a), (b)))
109252884aeSStefan Eßer #define bc_rand_add(a, b) (bc_rand_addition((a), (b)))
110252884aeSStefan Eßer 
111252884aeSStefan Eßer #define bc_rand_mul2(a, b) (bc_rand_multiply2((a), (b)))
112252884aeSStefan Eßer #define bc_rand_add2(a, b) (bc_rand_addition2((a), (b)))
113252884aeSStefan Eßer 
114252884aeSStefan Eßer #define BC_RAND_NOTMODIFIED(r) (((r)->inc.lo & 1) == 0)
115252884aeSStefan Eßer #define BC_RAND_ZERO(r) (!(r)->state.lo && !(r)->state.hi)
116252884aeSStefan Eßer 
117252884aeSStefan Eßer #define BC_RAND_CONSTANT(h, l) { .lo = (l), .hi = (h) }
118252884aeSStefan Eßer 
119252884aeSStefan Eßer #define BC_RAND_TRUNC(s) ((s).lo)
120252884aeSStefan Eßer #define BC_RAND_CHOP(s) ((s).hi)
121252884aeSStefan Eßer #define BC_RAND_ROTAMT(s) ((unsigned int) ((s).hi >> 58UL))
122252884aeSStefan Eßer 
123252884aeSStefan Eßer #define BC_RAND_BOTTOM32 (((uint_fast64_t) 0xffffffffULL))
124252884aeSStefan Eßer #define BC_RAND_TRUNC32(n) ((n) & BC_RAND_BOTTOM32)
125252884aeSStefan Eßer #define BC_RAND_CHOP32(n) ((n) >> 32)
126252884aeSStefan Eßer 
127252884aeSStefan Eßer #endif // BC_RAND_BUILTIN
128252884aeSStefan Eßer 
129252884aeSStefan Eßer #define BC_RAND_MULTIPLIER \
130252884aeSStefan Eßer 	BC_RAND_CONSTANT(2549297995355413924ULL, 4865540595714422341ULL)
131252884aeSStefan Eßer 
132252884aeSStefan Eßer #define BC_RAND_FOLD(s) ((BcRand) (BC_RAND_CHOP(s) ^ BC_RAND_TRUNC(s)))
133252884aeSStefan Eßer 
134252884aeSStefan Eßer #else // BC_LONG_BIT >= 64
135252884aeSStefan Eßer 
136252884aeSStefan Eßer #undef BC_RAND_BUILTIN
137252884aeSStefan Eßer #define BC_RAND_BUILTIN (1)
138252884aeSStefan Eßer 
139252884aeSStefan Eßer typedef uint32_t BcRand;
140252884aeSStefan Eßer 
141252884aeSStefan Eßer #define BC_RAND_ROTC (31)
142252884aeSStefan Eßer 
143252884aeSStefan Eßer typedef uint_fast64_t BcRandState;
144252884aeSStefan Eßer 
145252884aeSStefan Eßer #define bc_rand_mul(a, b) (((BcRandState) (a)) * ((BcRandState) (b)))
146252884aeSStefan Eßer #define bc_rand_add(a, b) (((BcRandState) (a)) + ((BcRandState) (b)))
147252884aeSStefan Eßer 
148252884aeSStefan Eßer #define bc_rand_mul2(a, b) (((BcRandState) (a)) * ((BcRandState) (b)))
149252884aeSStefan Eßer #define bc_rand_add2(a, b) (((BcRandState) (a)) + ((BcRandState) (b)))
150252884aeSStefan Eßer 
151252884aeSStefan Eßer #define BC_RAND_NOTMODIFIED(r) (((r)->inc & 1UL) == 0)
152252884aeSStefan Eßer #define BC_RAND_ZERO(r) (!(r)->state)
153252884aeSStefan Eßer 
154252884aeSStefan Eßer #define BC_RAND_CONSTANT UINT64_C
155252884aeSStefan Eßer #define BC_RAND_MULTIPLIER BC_RAND_CONSTANT(6364136223846793005)
156252884aeSStefan Eßer 
157252884aeSStefan Eßer #define BC_RAND_TRUNC(s) ((uint32_t) (s))
158252884aeSStefan Eßer #define BC_RAND_CHOP(s) ((uint32_t) ((s) >> 32UL))
159252884aeSStefan Eßer #define BC_RAND_ROTAMT(s) ((unsigned int) ((s) >> 59UL))
160252884aeSStefan Eßer 
161252884aeSStefan Eßer #define BC_RAND_FOLD(s) ((BcRand) ((((s) >> 18U) ^ (s)) >> 27U))
162252884aeSStefan Eßer 
163252884aeSStefan Eßer #endif // BC_LONG_BIT >= 64
164252884aeSStefan Eßer 
165252884aeSStefan Eßer #define BC_RAND_ROT(v, r) \
166252884aeSStefan Eßer 	((BcRand) (((v) >> (r)) | ((v) << ((0 - (r)) & BC_RAND_ROTC))))
167252884aeSStefan Eßer 
168252884aeSStefan Eßer #define BC_RAND_BITS (sizeof(BcRand) * CHAR_BIT)
169252884aeSStefan Eßer #define BC_RAND_STATE_BITS (sizeof(BcRandState) * CHAR_BIT)
170252884aeSStefan Eßer 
171252884aeSStefan Eßer #define BC_RAND_NUM_SIZE (BC_NUM_BIGDIG_LOG10 * 2 + 2)
172252884aeSStefan Eßer 
173252884aeSStefan Eßer #define BC_RAND_SRAND_BITS ((1 << CHAR_BIT) - 1)
174252884aeSStefan Eßer 
175252884aeSStefan Eßer typedef struct BcRNGData {
176252884aeSStefan Eßer 
177252884aeSStefan Eßer 	BcRandState state;
178252884aeSStefan Eßer 	BcRandState inc;
179252884aeSStefan Eßer 
180252884aeSStefan Eßer } BcRNGData;
181252884aeSStefan Eßer 
182252884aeSStefan Eßer typedef struct BcRNG {
183252884aeSStefan Eßer 
184252884aeSStefan Eßer 	BcVec v;
185252884aeSStefan Eßer 
186252884aeSStefan Eßer } BcRNG;
187252884aeSStefan Eßer 
188252884aeSStefan Eßer void bc_rand_init(BcRNG *r);
189252884aeSStefan Eßer #ifndef NDEBUG
190252884aeSStefan Eßer void bc_rand_free(BcRNG *r);
191252884aeSStefan Eßer #endif // NDEBUG
192252884aeSStefan Eßer 
193252884aeSStefan Eßer BcRand bc_rand_int(BcRNG *r);
194252884aeSStefan Eßer BcRand bc_rand_bounded(BcRNG *r, BcRand bound);
195252884aeSStefan Eßer void bc_rand_seed(BcRNG *r, ulong state1, ulong state2, ulong inc1, ulong inc2);
196252884aeSStefan Eßer void bc_rand_push(BcRNG *r);
197252884aeSStefan Eßer void bc_rand_pop(BcRNG *r, bool reset);
198252884aeSStefan Eßer void bc_rand_getRands(BcRNG *r, BcRand *s1, BcRand *s2, BcRand *i1, BcRand *i2);
19950696a6eSStefan Eßer void bc_rand_srand(BcRNGData *rng);
200252884aeSStefan Eßer 
201252884aeSStefan Eßer extern const BcRandState bc_rand_multiplier;
202252884aeSStefan Eßer 
2033aa99676SStefan Eßer #endif // BC_ENABLE_RAND
2043aa99676SStefan Eßer 
205252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
206252884aeSStefan Eßer 
207252884aeSStefan Eßer #endif // BC_RAND_H
208