xref: /freebsd/contrib/bc/include/rand.h (revision a970610a3af63b3f4df5b69d91c6b4093a00ed8f)
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  *
1310328f8bSStefan 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*a970610aSStefan Eßer  * Copyright (c) 2018-2024 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 
5344d4804dSStefan Eßer #if BC_ENABLE_LIBRARY
5444d4804dSStefan Eßer #define BC_RAND_USE_FREE (1)
5544d4804dSStefan Eßer #else // BC_ENABLE_LIBRARY
56103d7cdfSStefan Eßer #if BC_DEBUG
5744d4804dSStefan Eßer #define BC_RAND_USE_FREE (1)
58103d7cdfSStefan Eßer #else // BC_DEBUG
5944d4804dSStefan Eßer #define BC_RAND_USE_FREE (0)
60103d7cdfSStefan Eßer #endif // BC_DEBUG
6144d4804dSStefan Eßer #endif // BC_ENABLE_LIBRARY
623aa99676SStefan Eßer 
6344d4804dSStefan Eßer /**
6444d4804dSStefan Eßer  * A function to return a random unsigned long.
6544d4804dSStefan Eßer  * @param ptr  A void ptr to some data that will help generate the random ulong.
6644d4804dSStefan Eßer  * @return     The random ulong.
6744d4804dSStefan Eßer  */
6844d4804dSStefan Eßer typedef ulong (*BcRandUlong)(void* ptr);
69252884aeSStefan Eßer 
70252884aeSStefan Eßer #if BC_LONG_BIT >= 64
71252884aeSStefan Eßer 
7244d4804dSStefan Eßer // If longs are 64 bits, we have the option of 128-bit integers on some
7344d4804dSStefan Eßer // compilers. These two sections test that.
74252884aeSStefan Eßer #ifdef BC_RAND_BUILTIN
75252884aeSStefan Eßer #if BC_RAND_BUILTIN
76252884aeSStefan Eßer #ifndef __SIZEOF_INT128__
77252884aeSStefan Eßer #undef BC_RAND_BUILTIN
78252884aeSStefan Eßer #define BC_RAND_BUILTIN (0)
79252884aeSStefan Eßer #endif // __SIZEOF_INT128__
80252884aeSStefan Eßer #endif // BC_RAND_BUILTIN
81252884aeSStefan Eßer #endif // BC_RAND_BUILTIN
82252884aeSStefan Eßer 
83252884aeSStefan Eßer #ifndef BC_RAND_BUILTIN
84252884aeSStefan Eßer #ifdef __SIZEOF_INT128__
85252884aeSStefan Eßer #define BC_RAND_BUILTIN (1)
86252884aeSStefan Eßer #else // __SIZEOF_INT128__
87252884aeSStefan Eßer #define BC_RAND_BUILTIN (0)
88252884aeSStefan Eßer #endif // __SIZEOF_INT128__
89252884aeSStefan Eßer #endif // BC_RAND_BUILTIN
90252884aeSStefan Eßer 
9144d4804dSStefan Eßer /// The type for random integers.
92252884aeSStefan Eßer typedef uint64_t BcRand;
93252884aeSStefan Eßer 
9444d4804dSStefan Eßer /// A constant defined by PCG.
95252884aeSStefan Eßer #define BC_RAND_ROTC (63)
96252884aeSStefan Eßer 
97252884aeSStefan Eßer #if BC_RAND_BUILTIN
98252884aeSStefan Eßer 
9944d4804dSStefan Eßer /// A typedef for the PCG state.
100252884aeSStefan Eßer typedef __uint128_t BcRandState;
101252884aeSStefan Eßer 
10244d4804dSStefan Eßer /**
10344d4804dSStefan Eßer  * Multiply two integers, worrying about overflow.
10444d4804dSStefan Eßer  * @param a  The first integer.
10544d4804dSStefan Eßer  * @param b  The second integer.
10644d4804dSStefan Eßer  * @return   The product of the PCG states.
10744d4804dSStefan Eßer  */
108252884aeSStefan Eßer #define bc_rand_mul(a, b) (((BcRandState) (a)) * ((BcRandState) (b)))
10944d4804dSStefan Eßer 
11044d4804dSStefan Eßer /**
11144d4804dSStefan Eßer  * Add two integers, worrying about overflow.
11244d4804dSStefan Eßer  * @param a  The first integer.
11344d4804dSStefan Eßer  * @param b  The second integer.
11444d4804dSStefan Eßer  * @return   The sum of the PCG states.
11544d4804dSStefan Eßer  */
116252884aeSStefan Eßer #define bc_rand_add(a, b) (((BcRandState) (a)) + ((BcRandState) (b)))
117252884aeSStefan Eßer 
11844d4804dSStefan Eßer /**
11944d4804dSStefan Eßer  * Multiply two PCG states.
12044d4804dSStefan Eßer  * @param a  The first PCG state.
12144d4804dSStefan Eßer  * @param b  The second PCG state.
12244d4804dSStefan Eßer  * @return   The product of the PCG states.
12344d4804dSStefan Eßer  */
124252884aeSStefan Eßer #define bc_rand_mul2(a, b) (((BcRandState) (a)) * ((BcRandState) (b)))
12544d4804dSStefan Eßer 
12644d4804dSStefan Eßer /**
12744d4804dSStefan Eßer  * Add two PCG states.
12844d4804dSStefan Eßer  * @param a  The first PCG state.
12944d4804dSStefan Eßer  * @param b  The second PCG state.
13044d4804dSStefan Eßer  * @return   The sum of the PCG states.
13144d4804dSStefan Eßer  */
132252884aeSStefan Eßer #define bc_rand_add2(a, b) (((BcRandState) (a)) + ((BcRandState) (b)))
133252884aeSStefan Eßer 
13444d4804dSStefan Eßer /**
13544d4804dSStefan Eßer  * Figure out if the PRNG has been modified. Since the increment of the PRNG has
13644d4804dSStefan Eßer  * to be odd, we use the extra bit to store whether it has been modified or not.
13744d4804dSStefan Eßer  * @param r  The PRNG.
13844d4804dSStefan Eßer  * @return   True if the PRNG has *not* been modified, false otherwise.
13944d4804dSStefan Eßer  */
140252884aeSStefan Eßer #define BC_RAND_NOTMODIFIED(r) (((r)->inc & 1UL) == 0)
14144d4804dSStefan Eßer 
14244d4804dSStefan Eßer /**
14344d4804dSStefan Eßer  * Return true if the PRNG has not been seeded yet.
14444d4804dSStefan Eßer  * @param r  The PRNG.
14544d4804dSStefan Eßer  * @return   True if the PRNG has not been seeded yet, false otherwise.
14644d4804dSStefan Eßer  */
147252884aeSStefan Eßer #define BC_RAND_ZERO(r) (!(r)->state)
148252884aeSStefan Eßer 
14944d4804dSStefan Eßer /**
15044d4804dSStefan Eßer  * Returns a constant built from @a h and @a l.
15144d4804dSStefan Eßer  * @param h  The high 64 bits.
15244d4804dSStefan Eßer  * @param l  The low 64 bits.
15344d4804dSStefan Eßer  * @return   The constant built from @a h and @a l.
15444d4804dSStefan Eßer  */
155252884aeSStefan Eßer #define BC_RAND_CONSTANT(h, l) ((((BcRandState) (h)) << 64) + (BcRandState) (l))
156252884aeSStefan Eßer 
15744d4804dSStefan Eßer /**
15844d4804dSStefan Eßer  * Truncates a PCG state to the number of bits in a random integer.
15944d4804dSStefan Eßer  * @param s  The state to truncate.
16044d4804dSStefan Eßer  * @return   The truncated state.
16144d4804dSStefan Eßer  */
162252884aeSStefan Eßer #define BC_RAND_TRUNC(s) ((uint64_t) (s))
16344d4804dSStefan Eßer 
16444d4804dSStefan Eßer /**
16544d4804dSStefan Eßer  * Chops a PCG state in half and returns the top bits.
16644d4804dSStefan Eßer  * @param s  The state to chop.
16744d4804dSStefan Eßer  * @return   The chopped state's top bits.
16844d4804dSStefan Eßer  */
169252884aeSStefan Eßer #define BC_RAND_CHOP(s) ((uint64_t) ((s) >> 64UL))
17044d4804dSStefan Eßer 
17144d4804dSStefan Eßer /**
17244d4804dSStefan Eßer  * Rotates a PCG state.
17344d4804dSStefan Eßer  * @param s  The state to rotate.
17444d4804dSStefan Eßer  * @return   The rotated state.
17544d4804dSStefan Eßer  */
176252884aeSStefan Eßer #define BC_RAND_ROTAMT(s) ((unsigned int) ((s) >> 122UL))
177252884aeSStefan Eßer 
178252884aeSStefan Eßer #else // BC_RAND_BUILTIN
179252884aeSStefan Eßer 
18044d4804dSStefan Eßer /// A typedef for the PCG state.
18178bc019dSStefan Eßer typedef struct BcRandState
18278bc019dSStefan Eßer {
18344d4804dSStefan Eßer 	/// The low bits.
184252884aeSStefan Eßer 	uint_fast64_t lo;
18544d4804dSStefan Eßer 
18644d4804dSStefan Eßer 	/// The high bits.
187252884aeSStefan Eßer 	uint_fast64_t hi;
188252884aeSStefan Eßer 
189252884aeSStefan Eßer } BcRandState;
190252884aeSStefan Eßer 
19144d4804dSStefan Eßer /**
19244d4804dSStefan Eßer  * Multiply two integers, worrying about overflow.
19344d4804dSStefan Eßer  * @param a  The first integer.
19444d4804dSStefan Eßer  * @param b  The second integer.
19544d4804dSStefan Eßer  * @return   The product of the PCG states.
19644d4804dSStefan Eßer  */
197252884aeSStefan Eßer #define bc_rand_mul(a, b) (bc_rand_multiply((a), (b)))
19844d4804dSStefan Eßer 
19944d4804dSStefan Eßer /**
20044d4804dSStefan Eßer  * Add two integers, worrying about overflow.
20144d4804dSStefan Eßer  * @param a  The first integer.
20244d4804dSStefan Eßer  * @param b  The second integer.
20344d4804dSStefan Eßer  * @return   The sum of the PCG states.
20444d4804dSStefan Eßer  */
205252884aeSStefan Eßer #define bc_rand_add(a, b) (bc_rand_addition((a), (b)))
206252884aeSStefan Eßer 
20744d4804dSStefan Eßer /**
20844d4804dSStefan Eßer  * Multiply two PCG states.
20944d4804dSStefan Eßer  * @param a  The first PCG state.
21044d4804dSStefan Eßer  * @param b  The second PCG state.
21144d4804dSStefan Eßer  * @return   The product of the PCG states.
21244d4804dSStefan Eßer  */
213252884aeSStefan Eßer #define bc_rand_mul2(a, b) (bc_rand_multiply2((a), (b)))
21444d4804dSStefan Eßer 
21544d4804dSStefan Eßer /**
21644d4804dSStefan Eßer  * Add two PCG states.
21744d4804dSStefan Eßer  * @param a  The first PCG state.
21844d4804dSStefan Eßer  * @param b  The second PCG state.
21944d4804dSStefan Eßer  * @return   The sum of the PCG states.
22044d4804dSStefan Eßer  */
221252884aeSStefan Eßer #define bc_rand_add2(a, b) (bc_rand_addition2((a), (b)))
222252884aeSStefan Eßer 
22344d4804dSStefan Eßer /**
22444d4804dSStefan Eßer  * Figure out if the PRNG has been modified. Since the increment of the PRNG has
22544d4804dSStefan Eßer  * to be odd, we use the extra bit to store whether it has been modified or not.
22644d4804dSStefan Eßer  * @param r  The PRNG.
22744d4804dSStefan Eßer  * @return   True if the PRNG has *not* been modified, false otherwise.
22844d4804dSStefan Eßer  */
229252884aeSStefan Eßer #define BC_RAND_NOTMODIFIED(r) (((r)->inc.lo & 1) == 0)
23044d4804dSStefan Eßer 
23144d4804dSStefan Eßer /**
23244d4804dSStefan Eßer  * Return true if the PRNG has not been seeded yet.
23344d4804dSStefan Eßer  * @param r  The PRNG.
23444d4804dSStefan Eßer  * @return   True if the PRNG has not been seeded yet, false otherwise.
23544d4804dSStefan Eßer  */
236252884aeSStefan Eßer #define BC_RAND_ZERO(r) (!(r)->state.lo && !(r)->state.hi)
237252884aeSStefan Eßer 
23844d4804dSStefan Eßer /**
23944d4804dSStefan Eßer  * Returns a constant built from @a h and @a l.
24044d4804dSStefan Eßer  * @param h  The high 64 bits.
24144d4804dSStefan Eßer  * @param l  The low 64 bits.
24244d4804dSStefan Eßer  * @return   The constant built from @a h and @a l.
24344d4804dSStefan Eßer  */
244*a970610aSStefan Eßer #define BC_RAND_CONSTANT(h, l) { .lo = (l), .hi = (h) }
245252884aeSStefan Eßer 
24644d4804dSStefan Eßer /**
24744d4804dSStefan Eßer  * Truncates a PCG state to the number of bits in a random integer.
24844d4804dSStefan Eßer  * @param s  The state to truncate.
24944d4804dSStefan Eßer  * @return   The truncated state.
25044d4804dSStefan Eßer  */
251252884aeSStefan Eßer #define BC_RAND_TRUNC(s) ((s).lo)
25244d4804dSStefan Eßer 
25344d4804dSStefan Eßer /**
25444d4804dSStefan Eßer  * Chops a PCG state in half and returns the top bits.
25544d4804dSStefan Eßer  * @param s  The state to chop.
25644d4804dSStefan Eßer  * @return   The chopped state's top bits.
25744d4804dSStefan Eßer  */
258252884aeSStefan Eßer #define BC_RAND_CHOP(s) ((s).hi)
25944d4804dSStefan Eßer 
26044d4804dSStefan Eßer /**
26144d4804dSStefan Eßer  * Returns the rotate amount for a PCG state.
26244d4804dSStefan Eßer  * @param s  The state to rotate.
26344d4804dSStefan Eßer  * @return   The semi-rotated state.
26444d4804dSStefan Eßer  */
265252884aeSStefan Eßer #define BC_RAND_ROTAMT(s) ((unsigned int) ((s).hi >> 58UL))
266252884aeSStefan Eßer 
26744d4804dSStefan Eßer /// A 64-bit integer with the bottom 32 bits set.
268252884aeSStefan Eßer #define BC_RAND_BOTTOM32 (((uint_fast64_t) 0xffffffffULL))
26944d4804dSStefan Eßer 
27044d4804dSStefan Eßer /**
27144d4804dSStefan Eßer  * Returns the 32-bit truncated value of @a n.
27244d4804dSStefan Eßer  * @param n  The integer to truncate.
27344d4804dSStefan Eßer  * @return   The bottom 32 bits of @a n.
27444d4804dSStefan Eßer  */
27578bc019dSStefan Eßer #define BC_RAND_TRUNC32(n) ((n) & (BC_RAND_BOTTOM32))
27644d4804dSStefan Eßer 
27744d4804dSStefan Eßer /**
27844d4804dSStefan Eßer  * Returns the second 32 bits of @a n.
27944d4804dSStefan Eßer  * @param n  The integer to truncate.
28044d4804dSStefan Eßer  * @return   The second 32 bits of @a n.
28144d4804dSStefan Eßer  */
282252884aeSStefan Eßer #define BC_RAND_CHOP32(n) ((n) >> 32)
283252884aeSStefan Eßer 
284252884aeSStefan Eßer #endif // BC_RAND_BUILTIN
285252884aeSStefan Eßer 
28644d4804dSStefan Eßer /// A constant defined by PCG.
287252884aeSStefan Eßer #define BC_RAND_MULTIPLIER \
288252884aeSStefan Eßer 	BC_RAND_CONSTANT(2549297995355413924ULL, 4865540595714422341ULL)
289252884aeSStefan Eßer 
29044d4804dSStefan Eßer /**
29144d4804dSStefan Eßer  * Returns the result of a PCG fold.
29244d4804dSStefan Eßer  * @param s  The state to fold.
29344d4804dSStefan Eßer  * @return   The folded state.
29444d4804dSStefan Eßer  */
295252884aeSStefan Eßer #define BC_RAND_FOLD(s) ((BcRand) (BC_RAND_CHOP(s) ^ BC_RAND_TRUNC(s)))
296252884aeSStefan Eßer 
297252884aeSStefan Eßer #else // BC_LONG_BIT >= 64
298252884aeSStefan Eßer 
29944d4804dSStefan Eßer // If we are using 32-bit longs, we need to set these so.
300252884aeSStefan Eßer #undef BC_RAND_BUILTIN
301252884aeSStefan Eßer #define BC_RAND_BUILTIN (1)
302252884aeSStefan Eßer 
30344d4804dSStefan Eßer /// The type for random integers.
304252884aeSStefan Eßer typedef uint32_t BcRand;
305252884aeSStefan Eßer 
30644d4804dSStefan Eßer /// A constant defined by PCG.
307252884aeSStefan Eßer #define BC_RAND_ROTC (31)
308252884aeSStefan Eßer 
30944d4804dSStefan Eßer /// A typedef for the PCG state.
310252884aeSStefan Eßer typedef uint_fast64_t BcRandState;
311252884aeSStefan Eßer 
31244d4804dSStefan Eßer /**
31344d4804dSStefan Eßer  * Multiply two integers, worrying about overflow.
31444d4804dSStefan Eßer  * @param a  The first integer.
31544d4804dSStefan Eßer  * @param b  The second integer.
31644d4804dSStefan Eßer  * @return   The product of the PCG states.
31744d4804dSStefan Eßer  */
318252884aeSStefan Eßer #define bc_rand_mul(a, b) (((BcRandState) (a)) * ((BcRandState) (b)))
31944d4804dSStefan Eßer 
32044d4804dSStefan Eßer /**
32144d4804dSStefan Eßer  * Add two integers, worrying about overflow.
32244d4804dSStefan Eßer  * @param a  The first integer.
32344d4804dSStefan Eßer  * @param b  The second integer.
32444d4804dSStefan Eßer  * @return   The sum of the PCG states.
32544d4804dSStefan Eßer  */
326252884aeSStefan Eßer #define bc_rand_add(a, b) (((BcRandState) (a)) + ((BcRandState) (b)))
327252884aeSStefan Eßer 
32844d4804dSStefan Eßer /**
32944d4804dSStefan Eßer  * Multiply two PCG states.
33044d4804dSStefan Eßer  * @param a  The first PCG state.
33144d4804dSStefan Eßer  * @param b  The second PCG state.
33244d4804dSStefan Eßer  * @return   The product of the PCG states.
33344d4804dSStefan Eßer  */
334252884aeSStefan Eßer #define bc_rand_mul2(a, b) (((BcRandState) (a)) * ((BcRandState) (b)))
33544d4804dSStefan Eßer 
33644d4804dSStefan Eßer /**
33744d4804dSStefan Eßer  * Add two PCG states.
33844d4804dSStefan Eßer  * @param a  The first PCG state.
33944d4804dSStefan Eßer  * @param b  The second PCG state.
34044d4804dSStefan Eßer  * @return   The sum of the PCG states.
34144d4804dSStefan Eßer  */
342252884aeSStefan Eßer #define bc_rand_add2(a, b) (((BcRandState) (a)) + ((BcRandState) (b)))
343252884aeSStefan Eßer 
34444d4804dSStefan Eßer /**
34544d4804dSStefan Eßer  * Figure out if the PRNG has been modified. Since the increment of the PRNG has
34644d4804dSStefan Eßer  * to be odd, we use the extra bit to store whether it has been modified or not.
34744d4804dSStefan Eßer  * @param r  The PRNG.
34844d4804dSStefan Eßer  * @return   True if the PRNG has *not* been modified, false otherwise.
34944d4804dSStefan Eßer  */
350252884aeSStefan Eßer #define BC_RAND_NOTMODIFIED(r) (((r)->inc & 1UL) == 0)
35144d4804dSStefan Eßer 
35244d4804dSStefan Eßer /**
35344d4804dSStefan Eßer  * Return true if the PRNG has not been seeded yet.
35444d4804dSStefan Eßer  * @param r  The PRNG.
35544d4804dSStefan Eßer  * @return   True if the PRNG has not been seeded yet, false otherwise.
35644d4804dSStefan Eßer  */
357252884aeSStefan Eßer #define BC_RAND_ZERO(r) (!(r)->state)
358252884aeSStefan Eßer 
35944d4804dSStefan Eßer /**
36044d4804dSStefan Eßer  * Returns a constant built from a number.
36144d4804dSStefan Eßer  * @param n  The number.
36244d4804dSStefan Eßer  * @return   The constant built from @a n.
36344d4804dSStefan Eßer  */
36444d4804dSStefan Eßer #define BC_RAND_CONSTANT(n) UINT64_C(n)
36544d4804dSStefan Eßer 
36644d4804dSStefan Eßer /// A constant defined by PCG.
367252884aeSStefan Eßer #define BC_RAND_MULTIPLIER BC_RAND_CONSTANT(6364136223846793005)
368252884aeSStefan Eßer 
36944d4804dSStefan Eßer /**
37044d4804dSStefan Eßer  * Truncates a PCG state to the number of bits in a random integer.
37144d4804dSStefan Eßer  * @param s  The state to truncate.
37244d4804dSStefan Eßer  * @return   The truncated state.
37344d4804dSStefan Eßer  */
374252884aeSStefan Eßer #define BC_RAND_TRUNC(s) ((uint32_t) (s))
37544d4804dSStefan Eßer 
37644d4804dSStefan Eßer /**
37744d4804dSStefan Eßer  * Chops a PCG state in half and returns the top bits.
37844d4804dSStefan Eßer  * @param s  The state to chop.
37944d4804dSStefan Eßer  * @return   The chopped state's top bits.
38044d4804dSStefan Eßer  */
381252884aeSStefan Eßer #define BC_RAND_CHOP(s) ((uint32_t) ((s) >> 32UL))
38244d4804dSStefan Eßer 
38344d4804dSStefan Eßer /**
38444d4804dSStefan Eßer  * Returns the rotate amount for a PCG state.
38544d4804dSStefan Eßer  * @param s  The state to rotate.
38644d4804dSStefan Eßer  * @return   The semi-rotated state.
38744d4804dSStefan Eßer  */
388252884aeSStefan Eßer #define BC_RAND_ROTAMT(s) ((unsigned int) ((s) >> 59UL))
389252884aeSStefan Eßer 
39044d4804dSStefan Eßer /**
39144d4804dSStefan Eßer  * Returns the result of a PCG fold.
39244d4804dSStefan Eßer  * @param s  The state to fold.
39344d4804dSStefan Eßer  * @return   The folded state.
39444d4804dSStefan Eßer  */
395252884aeSStefan Eßer #define BC_RAND_FOLD(s) ((BcRand) ((((s) >> 18U) ^ (s)) >> 27U))
396252884aeSStefan Eßer 
397252884aeSStefan Eßer #endif // BC_LONG_BIT >= 64
398252884aeSStefan Eßer 
39944d4804dSStefan Eßer /**
40044d4804dSStefan Eßer  * Rotates @a v by @a r bits.
40144d4804dSStefan Eßer  * @param v  The value to rotate.
40244d4804dSStefan Eßer  * @param r  The amount to rotate by.
40344d4804dSStefan Eßer  * @return   The rotated value.
40444d4804dSStefan Eßer  */
405252884aeSStefan Eßer #define BC_RAND_ROT(v, r) \
406252884aeSStefan Eßer 	((BcRand) (((v) >> (r)) | ((v) << ((0 - (r)) & BC_RAND_ROTC))))
407252884aeSStefan Eßer 
40844d4804dSStefan Eßer /// The number of bits in a random integer.
409252884aeSStefan Eßer #define BC_RAND_BITS (sizeof(BcRand) * CHAR_BIT)
41044d4804dSStefan Eßer 
41144d4804dSStefan Eßer /// The number of bits in a PCG state.
412252884aeSStefan Eßer #define BC_RAND_STATE_BITS (sizeof(BcRandState) * CHAR_BIT)
413252884aeSStefan Eßer 
41444d4804dSStefan Eßer /// The size of a BcNum with the max random integer. This isn't exact; it's
41544d4804dSStefan Eßer /// actually rather crude. But it's always enough.
416252884aeSStefan Eßer #define BC_RAND_NUM_SIZE (BC_NUM_BIGDIG_LOG10 * 2 + 2)
417252884aeSStefan Eßer 
41844d4804dSStefan Eßer /// The mask for how many bits bc_rand_srand() can set per iteration.
419252884aeSStefan Eßer #define BC_RAND_SRAND_BITS ((1 << CHAR_BIT) - 1)
420252884aeSStefan Eßer 
42144d4804dSStefan Eßer /// The actual RNG data. These are the actual PRNG's.
42278bc019dSStefan Eßer typedef struct BcRNGData
42378bc019dSStefan Eßer {
42444d4804dSStefan Eßer 	/// The state.
425252884aeSStefan Eßer 	BcRandState state;
42644d4804dSStefan Eßer 
42744d4804dSStefan Eßer 	/// The increment and the modified bit.
428252884aeSStefan Eßer 	BcRandState inc;
429252884aeSStefan Eßer 
430252884aeSStefan Eßer } BcRNGData;
431252884aeSStefan Eßer 
43244d4804dSStefan Eßer /// The public PRNG. This is just a stack of PRNG's to maintain the globals
43344d4804dSStefan Eßer /// stack illusion.
43478bc019dSStefan Eßer typedef struct BcRNG
43578bc019dSStefan Eßer {
43644d4804dSStefan Eßer 	/// The stack of PRNG's.
437252884aeSStefan Eßer 	BcVec v;
438252884aeSStefan Eßer 
439252884aeSStefan Eßer } BcRNG;
440252884aeSStefan Eßer 
44144d4804dSStefan Eßer /**
44244d4804dSStefan Eßer  * Initializes a BcRNG.
44344d4804dSStefan Eßer  * @param r  The BcRNG to initialize.
44444d4804dSStefan Eßer  */
44578bc019dSStefan Eßer void
44678bc019dSStefan Eßer bc_rand_init(BcRNG* r);
447252884aeSStefan Eßer 
44844d4804dSStefan Eßer #if BC_RAND_USE_FREE
44944d4804dSStefan Eßer 
45044d4804dSStefan Eßer /**
45144d4804dSStefan Eßer  * Frees a BcRNG. This is only in debug builds because it would only be freed on
45244d4804dSStefan Eßer  * exit.
45344d4804dSStefan Eßer  * @param r  The BcRNG to free.
45444d4804dSStefan Eßer  */
45578bc019dSStefan Eßer void
45678bc019dSStefan Eßer bc_rand_free(BcRNG* r);
45744d4804dSStefan Eßer 
45844d4804dSStefan Eßer #endif // BC_RAND_USE_FREE
45944d4804dSStefan Eßer 
46044d4804dSStefan Eßer /**
46144d4804dSStefan Eßer  * Returns a random integer from the PRNG.
46244d4804dSStefan Eßer  * @param r  The PRNG.
46344d4804dSStefan Eßer  * @return   A random integer.
46444d4804dSStefan Eßer  */
46578bc019dSStefan Eßer BcRand
46678bc019dSStefan Eßer bc_rand_int(BcRNG* r);
46744d4804dSStefan Eßer 
46844d4804dSStefan Eßer /**
46944d4804dSStefan Eßer  * Returns a random integer from the PRNG bounded by @a bound. Bias is
47044d4804dSStefan Eßer  * eliminated.
47144d4804dSStefan Eßer  * @param r      The PRNG.
47244d4804dSStefan Eßer  * @param bound  The bound for the random integer.
47344d4804dSStefan Eßer  * @return       A bounded random integer.
47444d4804dSStefan Eßer  */
47578bc019dSStefan Eßer BcRand
47678bc019dSStefan Eßer bc_rand_bounded(BcRNG* r, BcRand bound);
47744d4804dSStefan Eßer 
47844d4804dSStefan Eßer /**
47944d4804dSStefan Eßer  * Seed the PRNG with the state in two parts and the increment in two parts.
48044d4804dSStefan Eßer  * @param r       The PRNG.
48144d4804dSStefan Eßer  * @param state1  The first part of the state.
48244d4804dSStefan Eßer  * @param state2  The second part of the state.
48344d4804dSStefan Eßer  * @param inc1    The first part of the increment.
48444d4804dSStefan Eßer  * @param inc2    The second part of the increment.
48544d4804dSStefan Eßer  */
48678bc019dSStefan Eßer void
48778bc019dSStefan Eßer bc_rand_seed(BcRNG* r, ulong state1, ulong state2, ulong inc1, ulong inc2);
48844d4804dSStefan Eßer 
48944d4804dSStefan Eßer /**
49044d4804dSStefan Eßer  * Pushes a new PRNG onto the PRNG stack.
49144d4804dSStefan Eßer  * @param r  The PRNG.
49244d4804dSStefan Eßer  */
49378bc019dSStefan Eßer void
49478bc019dSStefan Eßer bc_rand_push(BcRNG* r);
49544d4804dSStefan Eßer 
49644d4804dSStefan Eßer /**
49744d4804dSStefan Eßer  * Pops one or all but one items off of the PRNG stack.
49844d4804dSStefan Eßer  * @param r      The PRNG.
49944d4804dSStefan Eßer  * @param reset  True if all but one PRNG should be popped off the stack, false
50044d4804dSStefan Eßer  *               if only one should be popped.
50144d4804dSStefan Eßer  */
50278bc019dSStefan Eßer void
50378bc019dSStefan Eßer bc_rand_pop(BcRNG* r, bool reset);
50444d4804dSStefan Eßer 
50544d4804dSStefan Eßer /**
50644d4804dSStefan Eßer  * Returns, via pointers, the state of the PRNG in pieces.
50744d4804dSStefan Eßer  * @param r   The PRNG.
50844d4804dSStefan Eßer  * @param s1  The return value for the first part of the state.
50944d4804dSStefan Eßer  * @param s2  The return value for the second part of the state.
51044d4804dSStefan Eßer  * @param i1  The return value for the first part of the increment.
51144d4804dSStefan Eßer  * @param i2  The return value for the second part of the increment.
51244d4804dSStefan Eßer  */
51378bc019dSStefan Eßer void
51478bc019dSStefan Eßer bc_rand_getRands(BcRNG* r, BcRand* s1, BcRand* s2, BcRand* i1, BcRand* i2);
51544d4804dSStefan Eßer 
51644d4804dSStefan Eßer /**
51744d4804dSStefan Eßer  * Seed the PRNG with random data.
51844d4804dSStefan Eßer  * @param rng  The PRNG.
51944d4804dSStefan Eßer  */
52078bc019dSStefan Eßer void
52178bc019dSStefan Eßer bc_rand_srand(BcRNGData* rng);
522252884aeSStefan Eßer 
52344d4804dSStefan Eßer /// A reference to a constant multiplier.
524252884aeSStefan Eßer extern const BcRandState bc_rand_multiplier;
525252884aeSStefan Eßer 
526252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
527252884aeSStefan Eßer 
528252884aeSStefan Eßer #endif // BC_RAND_H
529