Program Listing for File Xoroshiro256plus.h¶
↰ Return to documentation for file (necsim/Xoroshiro256plus.h
)
//This file is part of necsim project which is released under MIT license.
//See file **LICENSE.txt** or visit https://opensource.org/licenses/MIT) for full license details.
#ifndef NECSIM_XOROSHIRO256PLUS_H
#define NECSIM_XOROSHIRO256PLUS_H
#include <iostream>
#include <cstdint>
#include <array>
namespace random_numbers
{
static inline uint64_t rotl(const uint64_t &value, int bits)
{
return (value << bits) | (value >> (64 - bits));
}
static inline double intToDouble(const uint64_t &i)
{
union Conversion
{
uint64_t i;
double d;
};
Conversion conversion{};
conversion.i = UINT64_C(0x3FF) << 52 | i >> 12;
return conversion.d - 1.0;
}
class SplitMix64
{
private:
uint64_t x; /* The state can be seeded with any value. */
public:
explicit SplitMix64(uint64_t seed) : x(seed)
{ }
uint64_t next()
{
uint64_t z = (x += UINT64_C(0x9E3779B97F4A7C15));
z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9);
z = (z ^ (z >> 27)) * UINT64_C(0x94D049BB133111EB);
return z ^ (z >> 31);
}
void shuffle()
{
for(unsigned int i = 0; i < 8; i++)
{
next();
}
}
double d01()
{
return intToDouble(next());
}
};
class Xoroshiro256plus
{
protected:
std::array<uint64_t, 4> shuffle_table;
public:
Xoroshiro256plus() : shuffle_table()
{
}
virtual ~Xoroshiro256plus() = default;
explicit Xoroshiro256plus(uint64_t seed) : shuffle_table()
{
setSeed(seed);
}
virtual void setSeed(uint64_t seed)
{
SplitMix64 seed_generator(seed);
// Shuffle the seed generator 8 times
seed_generator.shuffle();
for(auto &item : shuffle_table)
{
item = seed_generator.next();
}
}
uint64_t next()
{
const uint64_t result_plus = shuffle_table[0] + shuffle_table[3];
const uint64_t t = shuffle_table[1] << 17;
shuffle_table[2] ^= shuffle_table[0];
shuffle_table[3] ^= shuffle_table[1];
shuffle_table[1] ^= shuffle_table[2];
shuffle_table[0] ^= shuffle_table[3];
shuffle_table[2] ^= t;
shuffle_table[3] = rotl(shuffle_table[3], 45);
return result_plus;
}
double d01()
{
return intToDouble(next());
}
void jump()
{
static const uint64_t JUMP[] = {0x180ec6d33cfd0aba, 0xd5a61266f0c9392c, 0xa9582618e03fc9aa,
0x39abdc4529b1661c};
uint64_t s0 = 0;
uint64_t s1 = 0;
uint64_t s2 = 0;
uint64_t s3 = 0;
for(unsigned long i : JUMP)
for(int b = 0; b < 64; b++)
{
if(i & UINT64_C(1) << b)
{
s0 ^= shuffle_table[0];
s1 ^= shuffle_table[1];
s2 ^= shuffle_table[2];
s3 ^= shuffle_table[3];
}
next();
}
shuffle_table[0] = s0;
shuffle_table[1] = s1;
shuffle_table[2] = s2;
shuffle_table[3] = s3;
}
friend std::ostream &operator<<(std::ostream &os, const Xoroshiro256plus &x)
{
for(const auto &item: x.shuffle_table)
{
os << item << ",";
}
return os;
}
friend std::istream &operator>>(std::istream &is, Xoroshiro256plus &x)
{
char delim;
for(auto &i : x.shuffle_table)
{
is >> i >> delim;
}
return is;
}
};
}
#endif //NECSIM_XOROSHIRO256PLUS_H