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