Luna/kernel/src/rand/Mersenne.cpp

62 lines
1.6 KiB
C++

#define MODULE "rand"
#include "rand/Mersenne.h"
#include "assert.h"
#include <stddef.h>
typedef uint64_t word_t;
static const int STATE_SIZE = 312;
static const int MIDDLE = 156;
static const int INIT_SHIFT = 62;
static const uint64_t TWIST_MASK = 0xb5026f5aa96619e9;
static const uint64_t INIT_FACT = 6364136223846793005;
static const int SHIFT1 = 29;
static const uint64_t MASK1 = 0x5555555555555555;
static const int SHIFT2 = 17;
static const uint64_t MASK2 = 0x71d67fffeda60000;
static const int SHIFT3 = 37;
static const uint64_t MASK3 = 0xfff7eee000000000;
static const int SHIFT4 = 43;
static const word_t LOWER_MASK = 0x7fffffff;
static const word_t UPPER_MASK = (~(word_t)LOWER_MASK);
static word_t state[STATE_SIZE];
static size_t index = STATE_SIZE + 1;
void Mersenne::seed(uint64_t s)
{
index = STATE_SIZE;
state[0] = s;
for (size_t i = 1; i < STATE_SIZE; i++) state[i] = (INIT_FACT * (state[i - 1] ^ (state[i - 1] >> INIT_SHIFT))) + i;
}
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;
}
uint64_t Mersenne::get()
{
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;
}