X-Git-Url: http://git.draconx.ca/gitweb/cdecl99.git/blobdiff_plain/0a1c8a90e23304220f6602e98aba5f891a1350b2..HEAD:/t/rng.c diff --git a/t/rng.c b/t/rng.c index e442d99..63e0818 100644 --- a/t/rng.c +++ b/t/rng.c @@ -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 #if !TEST_RNG_NO_EXTERNAL_API # include "test.h" #endif #define B64(x) ((x) & 0xffffffffffffffffull) +#define B32(x) ((x) & 0xffffffffu) struct test_rng { unsigned long long state[4]; @@ -61,38 +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 += 0x9e3779b97f4a7c15ull); - z = B64((z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull); - z = B64((z ^ (z >> 27)) * 0x94d049bb133111ebull); + 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)) { + 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; }