/* 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; ri; 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; is[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