| #include <u.h> |
| #include <libc.h> |
| |
| /* |
| * algorithm by |
| * D. P. Mitchell & J. A. Reeds |
| */ |
| |
| #define LEN 607 |
| #define TAP 273 |
| #define MASK 0x7fffffffL |
| #define A 48271 |
| #define M 2147483647 |
| #define Q 44488 |
| #define R 3399 |
| #define NORM (1.0/(1.0+MASK)) |
| |
| static ulong rng_vec[LEN]; |
| static ulong* rng_tap = rng_vec; |
| static ulong* rng_feed = 0; |
| static Lock lk; |
| |
| static void |
| isrand(long seed) |
| { |
| long lo, hi, x; |
| int i; |
| |
| rng_tap = rng_vec; |
| rng_feed = rng_vec+LEN-TAP; |
| seed = seed%M; |
| if(seed < 0) |
| seed += M; |
| if(seed == 0) |
| seed = 89482311; |
| x = seed; |
| /* |
| * Initialize by x[n+1] = 48271 * x[n] mod (2**31 - 1) |
| */ |
| for(i = -20; i < LEN; i++) { |
| hi = x / Q; |
| lo = x % Q; |
| x = A*lo - R*hi; |
| if(x < 0) |
| x += M; |
| if(i >= 0) |
| rng_vec[i] = x; |
| } |
| } |
| |
| void |
| p9srand(long seed) |
| { |
| lock(&lk); |
| isrand(seed); |
| unlock(&lk); |
| } |
| |
| long |
| p9lrand(void) |
| { |
| ulong x; |
| |
| lock(&lk); |
| |
| rng_tap--; |
| if(rng_tap < rng_vec) { |
| if(rng_feed == 0) { |
| isrand(1); |
| rng_tap--; |
| } |
| rng_tap += LEN; |
| } |
| rng_feed--; |
| if(rng_feed < rng_vec) |
| rng_feed += LEN; |
| x = (*rng_feed + *rng_tap) & MASK; |
| *rng_feed = x; |
| |
| unlock(&lk); |
| |
| return x; |
| } |