62 lines
1.6 KiB
C++
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;
|
||
|
}
|