/* Portable pseudorandom number generator * Based on a 24,55 Fibonacci generator, using 55/503 rejection * c.f.- TAoCP, 3.2.2(7), for j=24,k=55,m=2^64 * * THIS FILE IS PUBLIC DOMAIN CODE. * * Written by Bob Adolf. * Attribution is appreciated but by no means legally required. * * This function is sufficient for most non-crypto applications. * It passes all but one of George Marsaglia's "diehard" randomness tests. * (overlapping 5-tuple permutations, which is allegedly buggy) */ #ifndef __PRNG_H__ #define __PRNG_H__ #include #include #include #include #define LAG1 (UINT16_C(24)) #define LAG2 (UINT16_C(55)) #define RAND_SSIZE ((UINT16_C(1)) << 6) #define RAND_SMASK (RAND_SSIZE - 1) #define RAND_EXHAUST_LIMIT LAG2 // 10x is a heuristic, it just needs to be large enough to remove correlation #define RAND_REFILL_COUNT ((LAG2 * 10) - RAND_EXHAUST_LIMIT) struct prng_rand_t { uint64_t s[RAND_SSIZE]; // Lags uint_fast16_t i; // Location of the current lag uint_fast16_t c; // Exhaustion count }; #define PRNG_RAND_MAX UINT64_MAX static inline uint64_t prng_rand(struct prng_rand_t* state) { uint_fast16_t i; uint_fast16_t r, new_rands = 0; if (!state->c) { // Randomness exhausted, run forward to refill new_rands += RAND_REFILL_COUNT + 1; state->c = RAND_EXHAUST_LIMIT - 1; } else { new_rands = 1; state->c--; } for (r = 0; r < new_rands; r++) { i = state->i; state->s[i & RAND_SMASK] = state->s[(i + RAND_SSIZE - LAG1) & RAND_SMASK] + state->s[(i + RAND_SSIZE - LAG2) & RAND_SMASK]; state->i++; } return state->s[i & RAND_SMASK]; } static inline void prng_srand(uint64_t seed, struct prng_rand_t* state) { uint_fast16_t i; // Naive seed state->c = RAND_EXHAUST_LIMIT; state->i = 0; state->s[0] = seed; for (i = 1; i < RAND_SSIZE; i++) { // Arbitrary magic, mostly to eliminate the effect of low-value seeds. // Probably could be better, but the run-up obviates any real need to. state->s[i] = i * (UINT64_C(2147483647)) + seed; } // Run forward 10,000 numbers for (i = 0; i < 10000; i++) { prng_rand(state); } } // Clean up our macros #undef LAG1 #undef LAG2 #undef RAND_SSIZE #undef RAND_SMASK #undef RAND_EXHAUST_LIMIT #undef RAND_REFILL_COUNT // PRNG_RAND_MAX is exported #endif