From 62a2b529542b26c073d3a3aab68f8ced50597653 Mon Sep 17 00:00:00 2001 From: Joe Nelson Date: Sat, 22 Dec 2018 22:03:51 -0600 Subject: [PATCH] Allow random values to scale up to 64-bits Improves precision in reservoir sampling --- rand.c | 22 ++++++++++------------ rand.h | 4 +++- randln.c | 3 ++- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/rand.c b/rand.c index 7dfb20a..4b6a8ad 100644 --- a/rand.c +++ b/rand.c @@ -53,21 +53,17 @@ unsigned long defensive_seed(void) * Alternative to the garbage implementation of rand() in many * systems such as FreeBSD and OS X. Uses xorshift. * - * Returns a value between 0 and DEFENSIVE_RAND_MAX, which on - * many platforms is smaller than what unsigned long can hold. + * Returns a value between 0 and DEFENSIVE_RAND_MAX. + * From https://nullprogram.com/blog/2018/07/31/ */ unsigned long defensive_rand() { - /* - * The long type should portably be at least 32 bits, and we - * mask the calculations to 32 bits in case long happens to be - * wider. The constants are tuned for a 32-bit type. - */ - unsigned long y = g_rand_state & DEFENSIVE_RAND_MAX; - y ^= (y << 13) & DEFENSIVE_RAND_MAX; - y ^= y >> 17; - y ^= (y << 5) & DEFENSIVE_RAND_MAX; - return (g_rand_state = y); + g_rand_state ^= g_rand_state >> 30; + g_rand_state *= 0xbf58476d1ce4e5b9UL; + g_rand_state ^= g_rand_state >> 27; + g_rand_state *= 0x94d049bb133111ebUL; + g_rand_state ^= g_rand_state >> 31; + return g_rand_state; } void defensive_srand(unsigned long s) @@ -88,6 +84,8 @@ unsigned long djb2hash(const unsigned char *str) /* It's better to combine entropic values this way rather * than e.g. adding them together. + * + * From http://www.pcg-random.org/posts/developing-a-seed_seq-alternative.html */ unsigned long mix(unsigned long x, unsigned long y) { diff --git a/rand.h b/rand.h index 206dff1..b9f6df5 100644 --- a/rand.h +++ b/rand.h @@ -1,7 +1,9 @@ #ifndef RAND_H #define RAND_H -#define DEFENSIVE_RAND_MAX 0xffffffffUL +#include + +#define DEFENSIVE_RAND_MAX ULONG_MAX void defensive_srand(unsigned long); unsigned long defensive_seed(void); diff --git a/randln.c b/randln.c index 4bfa117..9adbc64 100644 --- a/randln.c +++ b/randln.c @@ -53,7 +53,8 @@ void via_fseek(FILE *fp) if ((filesz = ftell(fp)) == -1) die_perror(NULL); - pos = (int)((double)defensive_rand() / ((double)DEFENSIVE_RAND_MAX + 1) * filesz); + pos = ((double)defensive_rand() / + ((double)DEFENSIVE_RAND_MAX)) * filesz; if (fseek(fp, pos, SEEK_SET) != 0) die_perror(NULL);