random.c (1453B)
1 #include <stdint.h> 2 #include <stdio.h> 3 #include <time.h> 4 5 static uint64_t globalstate; 6 7 /* 8 * PCG construction 9 * seeding the RNG means merely setting the initial state. 10 * the increment could also be made part of the seed, just make sure it's odd. 11 */ 12 uint32_t 13 rng32_r(uint64_t *state) 14 { 15 uint64_t oldstate = *state; 16 uint32_t r, v; 17 18 *state *= UINT64_C(0x9E3793492EEDC3F7); 19 *state += 0x1337; 20 21 r = oldstate >> (64 - 5); 22 v = (oldstate ^ (oldstate >> 18)) >> (32 - 5); 23 v = (v >> (-r & 31)) | (v << r); 24 return v; 25 } 26 27 uint32_t 28 rng32(void) 29 { 30 return rng32_r(&globalstate); 31 } 32 33 /* 34 * Based on optimized Lemire's method 35 * https://pcg-random.org/posts/bounded-rands.html 36 */ 37 uint32_t 38 rng32_bounded_r(uint64_t *state, uint32_t range) { 39 uint32_t x = rng32_r(state); 40 uint64_t m = (uint64_t)x * (uint64_t)range; 41 uint32_t l = (uint32_t)m; 42 if (l < range) { 43 uint32_t t = -range; 44 if (t >= range) { 45 t -= range; 46 if (t >= range) 47 t %= range; 48 } 49 while (l < t) { 50 x = rng32_r(state); 51 m = (uint64_t)x * (uint64_t)range; 52 l = (uint32_t)m; 53 } 54 } 55 return m >> 32; 56 } 57 58 uint64_t 59 rng32_bounded(uint32_t range) 60 { 61 return rng32_bounded_r(&globalstate, range); 62 } 63 64 /* Initialize state with somewhat random number */ 65 void 66 rng32_seed_r(uint64_t *state) 67 { 68 struct timespec ts; 69 clock_gettime(CLOCK_REALTIME, &ts); 70 *state = (intptr_t)&printf ^ ts.tv_sec ^ ((unsigned long)ts.tv_nsec * 0xAC5533CD); 71 } 72 73 void 74 rng32_seed(void) 75 { 76 rng32_seed_r(&globalstate); 77 }