1
/*
2
 * PCG64 Random Number Generation for C.
3
 *
4
 * Copyright 2014 Melissa O'Neill <oneill@pcg-random.org>
5
 * Copyright 2015 Robert Kern <robert.kern@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 *
19
 * For additional information about the PCG random number generation scheme,
20
 * including its license and other licensing options, visit
21
 *
22
 *     http://www.pcg-random.org
23
 *
24
 * Relicensed MIT in May 2019
25
 *
26
 * The MIT License
27
 *
28
 * PCG Random Number Generation for C.
29
 *
30
 * Copyright 2014 Melissa O'Neill <oneill@pcg-random.org>
31
 *
32
 * Permission is hereby granted, free of charge, to any person obtaining
33
 * a copy of this software and associated documentation files (the "Software"),
34
 * to deal in the Software without restriction, including without limitation
35
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
36
 * and/or sell copies of the Software, and to permit persons to whom the
37
 * Software is furnished to do so, subject to the following conditions:
38
 *
39
 * The above copyright notice and this permission notice shall be included in
40
 * all copies or substantial portions of the Software.
41
 *
42
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
44
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
45
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
46
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
47
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
48
 */
49

50
#include "pcg64.h"
51

52
extern inline void pcg_setseq_128_step_r(pcg_state_setseq_128 *rng);
53
extern inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state);
54
extern inline void pcg_setseq_128_srandom_r(pcg_state_setseq_128 *rng,
55
                                            pcg128_t initstate,
56
                                            pcg128_t initseq);
57
extern inline uint64_t
58
pcg_setseq_128_xsl_rr_64_random_r(pcg_state_setseq_128 *rng);
59
extern inline uint64_t
60
pcg_setseq_128_xsl_rr_64_boundedrand_r(pcg_state_setseq_128 *rng,
61
                                       uint64_t bound);
62
extern inline void pcg_setseq_128_advance_r(pcg_state_setseq_128 *rng,
63
                                            pcg128_t delta);
64

65
/* Multi-step advance functions (jump-ahead, jump-back)
66
 *
67
 * The method used here is based on Brown, "Random Number Generation
68
 * with Arbitrary Stride,", Transactions of the American Nuclear
69
 * Society (Nov. 1994).  The algorithm is very similar to fast
70
 * exponentiation.
71
 *
72
 * Even though delta is an unsigned integer, we can pass a
73
 * signed integer to go backwards, it just goes "the long way round".
74
 */
75

76
#ifndef PCG_EMULATED_128BIT_MATH
77

78 1
pcg128_t pcg_advance_lcg_128(pcg128_t state, pcg128_t delta, pcg128_t cur_mult,
79
                             pcg128_t cur_plus) {
80 1
  pcg128_t acc_mult = 1u;
81 1
  pcg128_t acc_plus = 0u;
82 1
  while (delta > 0) {
83 1
    if (delta & 1) {
84 1
      acc_mult *= cur_mult;
85 1
      acc_plus = acc_plus * cur_mult + cur_plus;
86
    }
87 1
    cur_plus = (cur_mult + 1) * cur_plus;
88 1
    cur_mult *= cur_mult;
89 1
    delta /= 2;
90
  }
91 1
  return acc_mult * state + acc_plus;
92
}
93

94
#else
95

96
pcg128_t pcg_advance_lcg_128(pcg128_t state, pcg128_t delta, pcg128_t cur_mult,
97
                             pcg128_t cur_plus) {
98
  pcg128_t acc_mult = PCG_128BIT_CONSTANT(0u, 1u);
99
  pcg128_t acc_plus = PCG_128BIT_CONSTANT(0u, 0u);
100
  while ((delta.high > 0) || (delta.low > 0)) {
101
    if (delta.low & 1) {
102
      acc_mult = pcg128_mult(acc_mult, cur_mult);
103
      acc_plus = pcg128_add(pcg128_mult(acc_plus, cur_mult), cur_plus);
104
    }
105
    cur_plus = pcg128_mult(pcg128_add(cur_mult, PCG_128BIT_CONSTANT(0u, 1u)),
106
                            cur_plus);
107
    cur_mult = pcg128_mult(cur_mult, cur_mult);
108
    delta.low >>= 1;
109
    delta.low += delta.high & 1;
110
    delta.high >>= 1;
111
  }
112
  return pcg128_add(pcg128_mult(acc_mult, state), acc_plus);
113
}
114

115
#endif
116

117
extern inline uint64_t pcg64_next64(pcg64_state *state);
118
extern inline uint32_t pcg64_next32(pcg64_state *state);
119

120 1
extern void pcg64_advance(pcg64_state *state, uint64_t *step) {
121
  pcg128_t delta;
122
#ifndef PCG_EMULATED_128BIT_MATH
123 1
  delta = (((pcg128_t)step[0]) << 64) | step[1];
124
#else
125
  delta.high = step[0];
126
  delta.low = step[1];
127
#endif
128 1
  pcg64_advance_r(state->pcg_state, delta);
129
}
130

131 1
extern void pcg64_set_seed(pcg64_state *state, uint64_t *seed, uint64_t *inc) {
132
  pcg128_t s, i;
133
#ifndef PCG_EMULATED_128BIT_MATH
134 1
  s = (((pcg128_t)seed[0]) << 64) | seed[1];
135 1
  i = (((pcg128_t)inc[0]) << 64) | inc[1];
136
#else
137
  s.high = seed[0];
138
  s.low = seed[1];
139
  i.high = inc[0];
140
  i.low = inc[1];
141
#endif
142 1
  pcg64_srandom_r(state->pcg_state, s, i);
143
}
144

145 1
extern void pcg64_get_state(pcg64_state *state, uint64_t *state_arr,
146
                            int *has_uint32, uint32_t *uinteger) {
147
  /*
148
   * state_arr contains state.high, state.low, inc.high, inc.low
149
   *    which are interpreted as the upper 64 bits (high) or lower
150
   *    64 bits of a uint128_t variable
151
   *
152
   */
153
#ifndef PCG_EMULATED_128BIT_MATH
154 1
  state_arr[0] = (uint64_t)(state->pcg_state->state >> 64);
155 1
  state_arr[1] = (uint64_t)(state->pcg_state->state & 0xFFFFFFFFFFFFFFFFULL);
156 1
  state_arr[2] = (uint64_t)(state->pcg_state->inc >> 64);
157 1
  state_arr[3] = (uint64_t)(state->pcg_state->inc & 0xFFFFFFFFFFFFFFFFULL);
158
#else
159
  state_arr[0] = (uint64_t)state->pcg_state->state.high;
160
  state_arr[1] = (uint64_t)state->pcg_state->state.low;
161
  state_arr[2] = (uint64_t)state->pcg_state->inc.high;
162
  state_arr[3] = (uint64_t)state->pcg_state->inc.low;
163
#endif
164 1
  has_uint32[0] = state->has_uint32;
165 1
  uinteger[0] = state->uinteger;
166
}
167

168 1
extern void pcg64_set_state(pcg64_state *state, uint64_t *state_arr,
169
                            int has_uint32, uint32_t uinteger) {
170
  /*
171
   * state_arr contains state.high, state.low, inc.high, inc.low
172
   *    which are interpreted as the upper 64 bits (high) or lower
173
   *    64 bits of a uint128_t variable
174
   *
175
   */
176
#ifndef PCG_EMULATED_128BIT_MATH
177 1
  state->pcg_state->state = (((pcg128_t)state_arr[0]) << 64) | state_arr[1];
178 1
  state->pcg_state->inc = (((pcg128_t)state_arr[2]) << 64) | state_arr[3];
179
#else
180
  state->pcg_state->state.high = state_arr[0];
181
  state->pcg_state->state.low = state_arr[1];
182
  state->pcg_state->inc.high = state_arr[2];
183
  state->pcg_state->inc.low = state_arr[3];
184
#endif
185 1
  state->has_uint32 = has_uint32;
186 1
  state->uinteger = uinteger;
187
}

Read our documentation on viewing source code .

Loading