diff --git a/libmisc/csrand.c b/libmisc/csrand.c index d4dabe54..2557fac8 100644 --- a/libmisc/csrand.c +++ b/libmisc/csrand.c @@ -9,17 +9,23 @@ #ident "$Id$" #include +#include #include #include #include #if HAVE_SYS_RANDOM_H #include #endif +#include "bit.h" #include "defines.h" #include "prototypes.h" #include "shadowlog.h" +static uint32_t csrand_uniform32(uint32_t n); +static unsigned long csrand_uniform_slow(unsigned long n); + + /* * Return a uniformly-distributed CS random u_long value. */ @@ -69,16 +75,37 @@ fail: /* * Return a uniformly-distributed CS random value in the interval [0, n-1]. - * - * Fast Random Integer Generation in an Interval - * ACM Transactions on Modeling and Computer Simulation 29 (1), 2019 - * */ unsigned long csrand_uniform(unsigned long n) { - unsigned long bound, rem; - unsigned __int128 r, mult; + if (n == 0 || n > UINT32_MAX) + return csrand_uniform_slow(n); + + return csrand_uniform32(n); +} + + +/* + * Return a uniformly-distributed CS random value in the interval [min, max]. + */ +unsigned long +csrand_interval(unsigned long min, unsigned long max) +{ + return csrand_uniform(max - min + 1) + min; +} + + +/* + * Fast Random Integer Generation in an Interval + * ACM Transactions on Modeling and Computer Simulation 29 (1), 2019 + * + */ +static uint32_t +csrand_uniform32(uint32_t n) +{ + uint32_t bound, rem; + uint64_t r, mult; if (n == 0) return csrand(); @@ -97,11 +124,18 @@ csrand_uniform(unsigned long n) } -/* - * Return a uniformly-distributed CS random value in the interval [min, max]. - */ -unsigned long -csrand_interval(unsigned long min, unsigned long max) +static unsigned long +csrand_uniform_slow(unsigned long n) { - return csrand_uniform(max - min + 1) + min; + unsigned long r, max, mask; + + max = n - 1; + mask = bit_ceil_wrapul(n) - 1; + + do { + r = csrand(); + r &= mask; // optimization + } while (r > max); // p = ((mask+1) % n) / (mask+1); W.C.: p=0.5 + + return r; }