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