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
55typedef 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
76typedef uint64_t BcRand;
77
78#define BC_RAND_ROTC (63)
79
80#if BC_RAND_BUILTIN
81
82typedef __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
101typedef 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
139typedef uint32_t BcRand;
140
141#define BC_RAND_ROTC (31)
142
143typedef 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
175typedef struct BcRNGData {
176
177	BcRandState state;
178	BcRandState inc;
179
180} BcRNGData;
181
182typedef struct BcRNG {
183
184	BcVec v;
185
186} BcRNG;
187
188void bc_rand_init(BcRNG *r);
189#ifndef NDEBUG
190void bc_rand_free(BcRNG *r);
191#endif // NDEBUG
192
193BcRand bc_rand_int(BcRNG *r);
194BcRand bc_rand_bounded(BcRNG *r, BcRand bound);
195void bc_rand_seed(BcRNG *r, ulong state1, ulong state2, ulong inc1, ulong inc2);
196void bc_rand_push(BcRNG *r);
197void bc_rand_pop(BcRNG *r, bool reset);
198void bc_rand_getRands(BcRNG *r, BcRand *s1, BcRand *s2, BcRand *i1, BcRand *i2);
199void bc_rand_srand(BcRNGData *rng);
200
201extern 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