1 /*
2  * *****************************************************************************
3  *
4  * Parts of this code are adapted from the following:
5  *
6  * PCG, A Family of Better Random Number Generators.
7  *
8  * You can find the original source code at:
9  *   https://github.com/imneme/pcg-c
10  *
11  * -----------------------------------------------------------------------------
12  *
13  * This code is under the following license:
14  *
15  * Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors
16  * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
17  *
18  * Permission is hereby granted, free of charge, to any person obtaining a copy
19  * of this software and associated documentation files (the "Software"), to deal
20  * in the Software without restriction, including without limitation the rights
21  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22  * copies of the Software, and to permit persons to whom the Software is
23  * furnished to do so, subject to the following conditions:
24  *
25  * The above copyright notice and this permission notice shall be included in
26  * all copies or substantial portions of the Software.
27  *
28  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34  * SOFTWARE.
35  *
36  * *****************************************************************************
37  *
38  * Definitions for the RNG.
39  *
40  */
41 
42 #ifndef BC_RAND_H
43 #define BC_RAND_H
44 
45 #include <stdint.h>
46 #include <inttypes.h>
47 
48 #include <vector.h>
49 #include <num.h>
50 
51 #if BC_ENABLE_EXTRA_MATH
52 
53 #if BC_ENABLE_RAND
54 
55 typedef ulong (*BcRandUlong)(void*);
56 
57 #if BC_LONG_BIT >= 64
58 
59 #ifdef BC_RAND_BUILTIN
60 #if BC_RAND_BUILTIN
61 #ifndef __SIZEOF_INT128__
62 #undef BC_RAND_BUILTIN
63 #define BC_RAND_BUILTIN (0)
64 #endif // __SIZEOF_INT128__
65 #endif // BC_RAND_BUILTIN
66 #endif // BC_RAND_BUILTIN
67 
68 #ifndef BC_RAND_BUILTIN
69 #ifdef __SIZEOF_INT128__
70 #define BC_RAND_BUILTIN (1)
71 #else // __SIZEOF_INT128__
72 #define BC_RAND_BUILTIN (0)
73 #endif // __SIZEOF_INT128__
74 #endif // BC_RAND_BUILTIN
75 
76 typedef uint64_t BcRand;
77 
78 #define BC_RAND_ROTC (63)
79 
80 #if BC_RAND_BUILTIN
81 
82 typedef __uint128_t BcRandState;
83 
84 #define bc_rand_mul(a, b) (((BcRandState) (a)) * ((BcRandState) (b)))
85 #define bc_rand_add(a, b) (((BcRandState) (a)) + ((BcRandState) (b)))
86 
87 #define bc_rand_mul2(a, b) (((BcRandState) (a)) * ((BcRandState) (b)))
88 #define bc_rand_add2(a, b) (((BcRandState) (a)) + ((BcRandState) (b)))
89 
90 #define BC_RAND_NOTMODIFIED(r) (((r)->inc & 1UL) == 0)
91 #define BC_RAND_ZERO(r) (!(r)->state)
92 
93 #define BC_RAND_CONSTANT(h, l) ((((BcRandState) (h)) << 64) + (BcRandState) (l))
94 
95 #define BC_RAND_TRUNC(s) ((uint64_t) (s))
96 #define BC_RAND_CHOP(s) ((uint64_t) ((s) >> 64UL))
97 #define BC_RAND_ROTAMT(s) ((unsigned int) ((s) >> 122UL))
98 
99 #else // BC_RAND_BUILTIN
100 
101 typedef struct BcRandState {
102 
103 	uint_fast64_t lo;
104 	uint_fast64_t hi;
105 
106 } BcRandState;
107 
108 #define bc_rand_mul(a, b) (bc_rand_multiply((a), (b)))
109 #define bc_rand_add(a, b) (bc_rand_addition((a), (b)))
110 
111 #define bc_rand_mul2(a, b) (bc_rand_multiply2((a), (b)))
112 #define bc_rand_add2(a, b) (bc_rand_addition2((a), (b)))
113 
114 #define BC_RAND_NOTMODIFIED(r) (((r)->inc.lo & 1) == 0)
115 #define BC_RAND_ZERO(r) (!(r)->state.lo && !(r)->state.hi)
116 
117 #define BC_RAND_CONSTANT(h, l) { .lo = (l), .hi = (h) }
118 
119 #define BC_RAND_TRUNC(s) ((s).lo)
120 #define BC_RAND_CHOP(s) ((s).hi)
121 #define BC_RAND_ROTAMT(s) ((unsigned int) ((s).hi >> 58UL))
122 
123 #define BC_RAND_BOTTOM32 (((uint_fast64_t) 0xffffffffULL))
124 #define BC_RAND_TRUNC32(n) ((n) & BC_RAND_BOTTOM32)
125 #define BC_RAND_CHOP32(n) ((n) >> 32)
126 
127 #endif // BC_RAND_BUILTIN
128 
129 #define BC_RAND_MULTIPLIER \
130 	BC_RAND_CONSTANT(2549297995355413924ULL, 4865540595714422341ULL)
131 
132 #define BC_RAND_FOLD(s) ((BcRand) (BC_RAND_CHOP(s) ^ BC_RAND_TRUNC(s)))
133 
134 #else // BC_LONG_BIT >= 64
135 
136 #undef BC_RAND_BUILTIN
137 #define BC_RAND_BUILTIN (1)
138 
139 typedef uint32_t BcRand;
140 
141 #define BC_RAND_ROTC (31)
142 
143 typedef uint_fast64_t BcRandState;
144 
145 #define bc_rand_mul(a, b) (((BcRandState) (a)) * ((BcRandState) (b)))
146 #define bc_rand_add(a, b) (((BcRandState) (a)) + ((BcRandState) (b)))
147 
148 #define bc_rand_mul2(a, b) (((BcRandState) (a)) * ((BcRandState) (b)))
149 #define bc_rand_add2(a, b) (((BcRandState) (a)) + ((BcRandState) (b)))
150 
151 #define BC_RAND_NOTMODIFIED(r) (((r)->inc & 1UL) == 0)
152 #define BC_RAND_ZERO(r) (!(r)->state)
153 
154 #define BC_RAND_CONSTANT UINT64_C
155 #define BC_RAND_MULTIPLIER BC_RAND_CONSTANT(6364136223846793005)
156 
157 #define BC_RAND_TRUNC(s) ((uint32_t) (s))
158 #define BC_RAND_CHOP(s) ((uint32_t) ((s) >> 32UL))
159 #define BC_RAND_ROTAMT(s) ((unsigned int) ((s) >> 59UL))
160 
161 #define BC_RAND_FOLD(s) ((BcRand) ((((s) >> 18U) ^ (s)) >> 27U))
162 
163 #endif // BC_LONG_BIT >= 64
164 
165 #define BC_RAND_ROT(v, r) \
166 	((BcRand) (((v) >> (r)) | ((v) << ((0 - (r)) & BC_RAND_ROTC))))
167 
168 #define BC_RAND_BITS (sizeof(BcRand) * CHAR_BIT)
169 #define BC_RAND_STATE_BITS (sizeof(BcRandState) * CHAR_BIT)
170 
171 #define BC_RAND_NUM_SIZE (BC_NUM_BIGDIG_LOG10 * 2 + 2)
172 
173 #define BC_RAND_SRAND_BITS ((1 << CHAR_BIT) - 1)
174 
175 typedef struct BcRNGData {
176 
177 	BcRandState state;
178 	BcRandState inc;
179 
180 } BcRNGData;
181 
182 typedef struct BcRNG {
183 
184 	BcVec v;
185 
186 } BcRNG;
187 
188 void bc_rand_init(BcRNG *r);
189 #ifndef NDEBUG
190 void bc_rand_free(BcRNG *r);
191 #endif // NDEBUG
192 
193 BcRand bc_rand_int(BcRNG *r);
194 BcRand bc_rand_bounded(BcRNG *r, BcRand bound);
195 void bc_rand_seed(BcRNG *r, ulong state1, ulong state2, ulong inc1, ulong inc2);
196 void bc_rand_push(BcRNG *r);
197 void bc_rand_pop(BcRNG *r, bool reset);
198 void bc_rand_getRands(BcRNG *r, BcRand *s1, BcRand *s2, BcRand *i1, BcRand *i2);
199 void bc_rand_srand(BcRNGData *rng);
200 
201 extern const BcRandState bc_rand_multiplier;
202 
203 #endif // BC_ENABLE_RAND
204 
205 #endif // BC_ENABLE_EXTRA_MATH
206 
207 #endif // BC_RAND_H
208