Last active
February 21, 2017 19:42
-
-
Save greenbagels/2efaf612b8540569a86e6c6075502103 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef XORSHIFT_H | |
#define XORSHIFT_H | |
#include <cstddef> //std::size_type | |
#include <limits> //std::numeric_limits | |
namespace xor | |
{ | |
namespace detail | |
{ | |
template <typename UIntType, std::size_t shiftlen, bool = shiftlen < static_cast<std::size_t>(std::numeric_limits<UIntType>::digits)> | |
struct Shift | |
{ | |
static const UIntType value = 0; | |
}; | |
template <typename UIntType, std::size_t shiftlen> | |
struct Shift<UIntType, shiftlen, true> | |
{ | |
static const UIntType value = UIntType(1) << shiftlen; | |
}; | |
} | |
template <typename UIntType, std::size_t UIntSize, std::size_t shft1, std::size_t shft2, std::size_t shft3> | |
class xor_engine | |
{ | |
static_assert(std::is_unsigned<UIntType>::value, "template argument " | |
"substituting UIntType not an unsigned integral type"); | |
static_assert(1u <= shft1 && shft1 <= std::numeric_limits<UIntType>::digits, | |
"template argument substituting shft1 out of bounds"); | |
static_assert(1u <= shft2 && shft2 <= std::numeric_limits<UIntType>::digits, | |
"template argument substituting shft2 out of bounds"); | |
static_assert(1u <= shft3 && shft3 <= std::numeric_limits<UIntType>::digits, | |
"template argument substituting shft3 out of bounds"); | |
public: | |
typedef UIntType result_type; | |
static const result_type default_seed = 4385u; //Value in GCC's lib seems arbitrary, why not ours, too | |
explicit xor_engine(result_type initial_state = default_seed) : current_state{initial_state} | |
{ | |
} | |
void seed(result_type initial_state = default_seed) | |
{ | |
current_state = initial_state; | |
} | |
static constexpr result_type min() | |
{ | |
return 0; //unsigned min | |
} | |
static constexpr result_type max() | |
{ | |
return detail::Shift<result_type, UIntSize>::value-1; | |
//Just in case sizeof(UIntType) >= UIntSize/CHAR_BIT | |
} | |
void discard(unsigned long long num) | |
{ | |
for(auto i = 0; i < num; ++i) | |
{ | |
gen_rand(); | |
} | |
} | |
static xor_engine& Instance() | |
{ | |
static xor_engine engine; | |
return engine; | |
} | |
result_type operator()() | |
{ | |
return gen_rand(); | |
} | |
//TODO: Add comparison operator | |
private: | |
result_type gen_rand() | |
{ //TODO: Optimize out the &= if the sizes match | |
current_state ^= (current_state << shft1); | |
current_state &= max(); //cut off extra bits if size > UIntSize | |
current_state ^= (current_state >> shft2); | |
current_state ^= (current_state << shft3); | |
current_state &= max(); //cut again | |
return current_state; | |
} | |
result_type current_state; | |
}; | |
typedef xor_engine<uint_fast32_t, 32, 2, 5, 15> xorshift_32; | |
typedef xor_engine<uint_fast64_t, 64, 10, 27, 59> xorshift_64; | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment