X-Git-Url: http://git.draconx.ca/gitweb/cdecl99.git/blobdiff_plain/1c3b0c0e6f9339e76e42f6393e554c7dfc58e205..HEAD:/t/rng.c diff --git a/t/rng.c b/t/rng.c index 8ae2f13..63e0818 100644 --- a/t/rng.c +++ b/t/rng.c @@ -1,6 +1,6 @@ /* * Simple random number generator for testing. - * Copyright © 2022 Nick Bowler + * Copyright © 2022-2024 Nick Bowler * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,24 +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 +#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]; @@ -61,52 +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); } -#if HAVE_STRTOULL -# define STRTOULL strtoull -#elif HAVE___STRTOULL -/* HP-UX 11 has __strtoull in */ -# define STRTOULL __strtoull -#else -/* - * Just fall back to strtoul -- in the worst case we just lose the ability - * to set all 64 bits of the seed. - */ -# define STRTOULL strtoul -#endif +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; + test_uintmax seed_val; struct test_rng *rng; - char *end; + uint_least32_t seed; - errno = 0; - seed = STRTOULL(seed_str, &end, 0); - if (*end != 0) { - fprintf(stderr, "%s: invalid seed\n", seed_str); - return NULL; - } else if (errno != 0) { - fprintf(stderr, "%s: invalid seed: %s\n", - seed_str, strerror(errno)); + 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; } @@ -116,20 +116,6 @@ void test_rng_free(struct test_rng *rng) free(rng); } -#define BITS_PER_FP_DIGIT ( FLT_RADIX < 4 ? 1 \ - : FLT_RADIX < 8 ? 2 \ - : FLT_RADIX < 16 ? 3 \ - : FLT_RADIX < 32 ? 4 \ - : 5 ) - -double test_rng_uniform(struct test_rng *rng) -{ - unsigned long long val = xoshiro256p(rng->state); - int prec = MIN(64, DBL_MANT_DIG*BITS_PER_FP_DIGIT); - - return ldexp(val >> (64-prec), -prec); -} - /* Calculate the least power of two greater than val, minus 1. */ static unsigned rng_mask(unsigned val) { @@ -155,3 +141,4 @@ unsigned test_rng_uniform_int(struct test_rng *rng, unsigned max) return val; } +#endif