1 /*
2 * PCG Random Number Generation for C.
3 *
4 * Copyright 2014 Melissa O'Neill <oneill@pcg-random.org>
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * For additional information about the PCG random number generation scheme,
19 * including its license and other licensing options, visit
20 *
21 * http://www.pcg-random.org
22 */
23
24 /*
25 * This file was mechanically generated from tests/check-pcg32.c
26 */
27
28 #include <stdio.h>
29 #include <stddef.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <stdbool.h>
33 #include <time.h>
34 #include <string.h>
35
36 #include "pcg_basic.h"
37
38 /*
39 * This code shows how you can cope if you're on a 32-bit platform (or a
40 * 64-bit platform with a mediocre compiler) that doesn't support 128-bit math,
41 * or if you're using the basic version of the library which only provides
42 * 32-bit generation.
43 *
44 * Here we build a 64-bit generator by tying together two 32-bit generators.
45 * Note that we can do this because we set up the generators so that each
46 * 32-bit generator has a *totally different* different output sequence
47 * -- if you tied together two identical generators, that wouldn't be nearly
48 * as good.
49 *
50 * For simplicity, we keep the period fixed at 2^64. The state space is
51 * approximately 2^254 (actually 2^64 * 2^64 * 2^63 * (2^63 - 1)), which
52 * is huge.
53 */
54
55 typedef struct {
56 pcg32_random_t gen[2];
57 } pcg32x2_random_t;
58
pcg32x2_srandom_r(pcg32x2_random_t * rng,uint64_t seed1,uint64_t seed2,uint64_t seq1,uint64_t seq2)59 void pcg32x2_srandom_r(pcg32x2_random_t* rng, uint64_t seed1, uint64_t seed2,
60 uint64_t seq1, uint64_t seq2)
61 {
62 uint64_t mask = ~0ull >> 1;
63 // The stream for each of the two generators *must* be distinct
64 if ((seq1 & mask) == (seq2 & mask))
65 seq2 = ~seq2;
66 pcg32_srandom_r(rng->gen, seed1, seq1);
67 pcg32_srandom_r(rng->gen+1, seed2, seq2);
68 }
69
pcg32x2_random_r(pcg32x2_random_t * rng)70 uint64_t pcg32x2_random_r(pcg32x2_random_t* rng)
71 {
72 return ((uint64_t)(pcg32_random_r(rng->gen)) << 32)
73 | pcg32_random_r(rng->gen+1);
74 }
75
76 /* See other definitons of ..._boundedrand_r for an explanation of this code. */
77
pcg32x2_boundedrand_r(pcg32x2_random_t * rng,uint64_t bound)78 uint64_t pcg32x2_boundedrand_r(pcg32x2_random_t* rng, uint64_t bound)
79 {
80 uint64_t threshold = -bound % bound;
81 for (;;) {
82 uint64_t r = pcg32x2_random_r(rng);
83 if (r >= threshold)
84 return r % bound;
85 }
86 }
87
88 int dummy_global;
89
main(int argc,char ** argv)90 int main(int argc, char** argv)
91 {
92 // Read command-line options
93
94 int rounds = 5;
95 bool nondeterministic_seed = false;
96 int round, i;
97
98 ++argv;
99 --argc;
100 if (argc > 0 && strcmp(argv[0], "-r") == 0) {
101 nondeterministic_seed = true;
102 ++argv;
103 --argc;
104 }
105 if (argc > 0) {
106 rounds = atoi(argv[0]);
107 }
108
109 // In this version of the code, we'll use our custom rng rather than
110 // one of the provided ones.
111
112 pcg32x2_random_t rng;
113
114 // You should *always* seed the RNG. The usual time to do it is the
115 // point in time when you create RNG (typically at the beginning of the
116 // program).
117 //
118 // pcg32x2_srandom_r takes four 64-bit constants (the initial state, and
119 // the rng sequence selector; rngs with different sequence selectors will
120 // *never* have random sequences that coincide, at all) - the code below
121 // shows three possible ways to do so.
122
123 if (nondeterministic_seed) {
124 // Seed with external entropy -- the time and some program addresses
125 // (which will actually be somewhat random on most modern systems).
126 // A better solution, entropy_getbytes, using /dev/random, is provided
127 // in the full library.
128
129 pcg32x2_srandom_r(&rng, time(NULL) ^ (intptr_t)&printf,
130 ~time(NULL) ^ (intptr_t)&pcg32_random_r,
131 (intptr_t)&rounds,
132 (intptr_t)&dummy_global);
133 } else {
134 // Seed with a fixed constant
135
136 pcg32x2_srandom_r(&rng, 42u, 42u, 54u, 54u);
137 }
138
139 printf("pcg32x2_random_r:\n"
140 " - result: 64-bit unsigned int (uint64_t)\n"
141 " - period: 2^64 (* ~2^126 streams)\n"
142 " - state space: ~2^254\n"
143 " - state type: pcg32x2_random_t (%zu bytes)\n"
144 " - output func: XSH-RR (x 2)\n"
145 "\n",
146 sizeof(pcg32x2_random_t));
147
148 for (round = 1; round <= rounds; ++round) {
149 printf("Round %d:\n", round);
150 /* Make some 32-bit numbers */
151 printf(" 64bit:");
152 for (i = 0; i < 6; ++i) {
153 if (i > 0 && i % 3 == 0)
154 printf("\n\t");
155 printf(" 0x%016llx", pcg32x2_random_r(&rng));
156 }
157 printf("\n");
158
159 /* Toss some coins */
160 printf(" Coins: ");
161 for (i = 0; i < 65; ++i)
162 printf("%c", pcg32x2_boundedrand_r(&rng, 2) ? 'H' : 'T');
163 printf("\n");
164
165 /* Roll some dice */
166 printf(" Rolls:");
167 for (i = 0; i < 33; ++i) {
168 printf(" %d", (int)pcg32x2_boundedrand_r(&rng, 6) + 1);
169 }
170 printf("\n");
171
172 /* Deal some cards */
173 enum { SUITS = 4, NUMBERS = 13, CARDS = 52 };
174 char cards[CARDS];
175
176 for (i = 0; i < CARDS; ++i)
177 cards[i] = i;
178
179 for (i = CARDS; i > 1; --i) {
180 int chosen = pcg32x2_boundedrand_r(&rng, i);
181 char card = cards[chosen];
182 cards[chosen] = cards[i - 1];
183 cards[i - 1] = card;
184 }
185
186 printf(" Cards:");
187 static const char number[] = {'A', '2', '3', '4', '5', '6', '7',
188 '8', '9', 'T', 'J', 'Q', 'K'};
189 static const char suit[] = {'h', 'c', 'd', 's'};
190 for (i = 0; i < CARDS; ++i) {
191 printf(" %c%c", number[cards[i] / SUITS], suit[cards[i] % SUITS]);
192 if ((i + 1) % 22 == 0)
193 printf("\n\t");
194 }
195 printf("\n");
196
197 printf("\n");
198 }
199
200 return 0;
201 }
202