apio
45afd3e243
Much better now. Also, it is seeded by reading from /dev/random at startup. Not sure if that's the best idea, but we'll see.
64 lines
1.4 KiB
C++
64 lines
1.4 KiB
C++
#include <assert.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
|
|
typedef uint32_t word_t;
|
|
#define STATE_SIZE 624
|
|
#define MIDDLE 397
|
|
#define INIT_SHIFT 30
|
|
#define INIT_FACT 1812433253
|
|
#define TWIST_MASK 0x9908b0df
|
|
#define SHIFT1 11
|
|
#define MASK1 0xffffffff
|
|
#define SHIFT2 7
|
|
#define MASK2 0x9d2c5680
|
|
#define SHIFT3 15
|
|
#define MASK3 0xefc60000
|
|
#define SHIFT4 18
|
|
|
|
#define LOWER_MASK 0x7fffffff
|
|
#define UPPER_MASK (~(word_t)LOWER_MASK)
|
|
|
|
static word_t state[STATE_SIZE];
|
|
static size_t index = STATE_SIZE + 1;
|
|
|
|
static void twist()
|
|
{
|
|
for (size_t i = 0; i < STATE_SIZE; i++)
|
|
{
|
|
word_t x = (state[i] & UPPER_MASK) | (state[(i + 1) % STATE_SIZE] & LOWER_MASK);
|
|
x = (x >> 1) ^ (x & 1 ? TWIST_MASK : 0);
|
|
state[i] = state[(i + MIDDLE) % STATE_SIZE] ^ x;
|
|
}
|
|
index = 0;
|
|
}
|
|
|
|
extern "C"
|
|
{
|
|
int rand()
|
|
{
|
|
if (index >= STATE_SIZE)
|
|
{
|
|
assert(index == STATE_SIZE && "Mersenne generator was never seeded");
|
|
twist();
|
|
}
|
|
|
|
word_t y = state[index];
|
|
y ^= (y >> SHIFT1) & MASK1;
|
|
y ^= (y << SHIFT2) & MASK2;
|
|
y ^= (y << SHIFT3) & MASK3;
|
|
y ^= y >> SHIFT4;
|
|
|
|
index++;
|
|
return y;
|
|
}
|
|
|
|
void srand(unsigned int seed)
|
|
{
|
|
index = STATE_SIZE;
|
|
state[0] = seed;
|
|
for (size_t i = 1; i < STATE_SIZE; i++)
|
|
state[i] = (word_t)((INIT_FACT * (state[i - 1] ^ (state[i - 1] >> INIT_SHIFT))) + i);
|
|
}
|
|
} |