sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | LICENSE

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 }