X-Git-Url: http://git.draconx.ca/gitweb/cdecl99.git/blobdiff_plain/198b77a35965824ae4115a3488d3ecb72431c5f6..HEAD:/t/rng.c diff --git a/t/rng.c b/t/rng.c index 3842d3d..63e0818 100644 --- a/t/rng.c +++ b/t/rng.c @@ -15,22 +15,25 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * The RNG implementation is adapted from xoshiro256+ and splitmix64 - * by David Blackman and Sebastiano Vigna, originally distributed under - * the Creative Commons Zero public domain dedication. + * The RNG implementation is adapted from xoshiro256+ by David Blackman + * and Sebastiano Vigna, originally distributed under the Creative Commons + * Zero public domain dedication. */ #include #include #include #include -#include #include #include +#include -#include "test.h" +#if !TEST_RNG_NO_EXTERNAL_API +# include "test.h" +#endif -#define B64(x) ((x) & 0xffffffffffffffff) +#define B64(x) ((x) & 0xffffffffffffffffull) +#define B32(x) ((x) & 0xffffffffu) struct test_rng { unsigned long long state[4]; @@ -59,37 +62,51 @@ static unsigned long long xoshiro256p(unsigned long long *s) return ret; } -static unsigned long long splitmix64(unsigned long long *state) +/* + * 32-bit random number generator for seed expansion. + * + * The output filter is from the public domain MurmurHash3 by Austin Appleby. + * + * The state is incremented by the fractional part of the golden ratio, + * i.e., floor( (sqrt(5)-1)/2 * 2**32 ) + */ +static uint_least32_t splitmix32(uint_least32_t *state) { - unsigned long long z; + uint_least32_t z; - z = B64(*state += 0x9e3779b97f4a7c15); - z = B64((z ^ (z >> 30)) * 0xbf58476d1ce4e5b9); - z = B64((z ^ (z >> 27)) * 0x94d049bb133111eb); + z = B32(*state += 0x9e3779b9); + z = B32((z ^ (z >> 16)) * 0x85ebca6b); + z = B32((z ^ (z >> 13)) * 0xc2b2ae35); - return z ^ (z >> 31); + return z ^ (z >> 16); } +static uint_least64_t seed64(uint_least32_t *state) +{ + uint_least64_t x; + + x = splitmix32(state); + return (x << 32) | splitmix32(state); +} + +#if !TEST_RNG_NO_EXTERNAL_API struct test_rng *test_rng_alloc(const char *seed_str) { - unsigned long long seed; - uintmax_t limit, seed_val; + test_uintmax seed_val; struct test_rng *rng; + uint_least32_t seed; - limit = (uintmax_t)0xffffffff; - limit |= (limit << 16 << 16); - - if (!test_strtoumax(&seed_val, seed_str, limit)) { - fprintf(stderr, "%s: invalid seed\n", seed_str); + if (!test_strtoumax(&seed_val, seed_str, 0xffffffff)) { + print_error("%s: invalid seed", seed_str); return NULL; } seed = seed_val; rng = malloc_nofail(sizeof *rng); - rng->state[0] = splitmix64(&seed); - rng->state[1] = splitmix64(&seed); - rng->state[2] = splitmix64(&seed); - rng->state[3] = splitmix64(&seed); + rng->state[0] = seed64(&seed); + rng->state[1] = seed64(&seed); + rng->state[2] = seed64(&seed); + rng->state[3] = seed64(&seed); return rng; } @@ -124,3 +141,4 @@ unsigned test_rng_uniform_int(struct test_rng *rng, unsigned max) return val; } +#endif