98 lines
2.5 KiB
C
98 lines
2.5 KiB
C
|
/* 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 <inttypes.h>
|
||
|
#include <stdint.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#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
|