Charades
xoroshiro.h
1 #pragma once
2 
3 #include "pup.h"
4 
5 #include <cstdint>
6 #include <iostream>
7 #include <limits>
8 #include <type_traits>
9 
11 private:
12  static constexpr uint64_t S0 = 0x9b60939458e17d7e;
13  static constexpr uint64_t S1 = 0xd737232eeccdf7ed;
14 
15  static constexpr inline uint64_t rotl(const uint64_t x, int k) {
16  return (x << k) | (x >> (64 - k));
17  }
18 
19  uint64_t _s[2];
20  uint64_t _count = 0;
21 
22  constexpr xoroshiro128plus(uint64_t s0, uint64_t s1) noexcept
23  : _s{s0, s1}, _count(0) {}
24 
25 public:
26  using result_type = uint64_t;
27 
28  constexpr xoroshiro128plus() noexcept : xoroshiro128plus(S0, S1) {}
29 
30  constexpr xoroshiro128plus(const xoroshiro128plus& rhs) noexcept
31  : _s{rhs._s[0], rhs._s[1]}, _count(rhs._count) {}
32 
33  xoroshiro128plus(result_type r) noexcept {
34  seed(r);
35  }
36 
37  template <typename Sseq, typename = typename std::enable_if<!std::is_same<Sseq, xoroshiro128plus>::value>::type>
38  xoroshiro128plus(Sseq& q) {
39  seed(q);
40  }
41 
42  auto operator = (const xoroshiro128plus& rhs) noexcept -> xoroshiro128plus& {
43  _s[0] = rhs._s[0];
44  _s[1] = rhs._s[1];
45  _count = rhs._count;
46  return *this;
47  }
48 
49  static constexpr auto min() noexcept -> result_type { return std::numeric_limits<result_type>::min(); }
50  static constexpr auto max() noexcept -> result_type { return std::numeric_limits<result_type>::max(); }
51 
52  constexpr auto operator () () noexcept -> result_type {
53  const uint64_t result = _s[0] + _s[1];
54 
55  const uint64_t s0 = rotl(_s[0], 24) ^ _s[0] ^ _s[1] ^ ((_s[0] ^ _s[1]) << 16);
56  const uint64_t s1 = rotl(_s[0] ^ _s[1], 37);
57  _s[0] = s0;
58  _s[1] = s1;
59 
60  ++_count;
61  return result;
62  }
63 
64  constexpr void prev() noexcept {
65  const uint64_t x = rotl(_s[1], 27);
66  _s[0] = rotl(_s[0] ^ x ^ (x << 16), 40);
67  _s[1] = _s[0] ^ x;
68  --_count;
69  }
70 
71  constexpr void seed() {
72  _s[0] = S0;
73  _s[1] = S1;
74  }
75 
76  constexpr void seed(result_type r) {
77  uint64_t z = r += 0x9E3779B97F4A7C15;
78  z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9;
79  z = (z ^ (z >> 27)) * 0x94D049BB133111EB;
80  _s[0] = z ^ (z >> 31);
81 
82  z = r += 0x9E3779B97F4A7C15;
83  z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9;
84  z = (z ^ (z >> 27)) * 0x94D049BB133111EB;
85  _s[1] = z ^ (z >> 31);
86  }
87 
88  template <typename Sseq>
89  typename std::enable_if<std::is_class<Sseq>::value>::type seed(Sseq& q) {
90  q.generate(_s, _s + 2);
91  }
92 
93  constexpr void discard(uint64_t n) noexcept {
94  for (unsigned long long i = 0; i < n; ++i) {
95  operator () ();
96  }
97  }
98 
99  void jump() noexcept {
100  static const uint64_t JUMP[2] = {
101  0xDF900204d8f554A5,
102  0x170865DF4B3201FC
103  };
104 
105  uint64_t s0 = 0;
106  uint64_t s1 = 0;
107 
108  for (int b = 0; b < 64; ++b) {
109  if (JUMP[0] & UINT64_C(1) << b) {
110  s0 ^= _s[0];
111  s1 ^= _s[1];
112  }
113  operator () ();
114  }
115 
116  for (int b = 0; b < 64; ++b) {
117  if (JUMP[1] & UINT64_C(1) << b) {
118  s0 ^= _s[0];
119  s1 ^= _s[1];
120  }
121  operator () ();
122  }
123 
124  _s[0] = s0;
125  _s[1] = s1;
126  _count = 0;
127  }
128 
129  void long_jump() noexcept {
130  static const uint64_t JUMP[2] = {
131  0xD2A98B26625EEE7B,
132  0xDDDF9B1090AA7AC1
133  };
134 
135  uint64_t s0 = 0;
136  uint64_t s1 = 0;
137 
138  for (int b = 0; b < 64; ++b) {
139  if (JUMP[0] & UINT64_C(1) << b) {
140  s0 ^= _s[0];
141  s1 ^= _s[1];
142  }
143  operator () ();
144  }
145 
146  for (int b = 0; b < 64; ++b) {
147  if (JUMP[1] & UINT64_C(1) << b) {
148  s0 ^= _s[0];
149  s1 ^= _s[1];
150  }
151  operator () ();
152  }
153 
154  _s[0] = s0;
155  _s[1] = s1;
156  _count = 0;
157  }
158 
159  constexpr uint64_t count() noexcept { return _count; }
160 
161  virtual void pup(PUP::er& p) {
162  p | _s[0];
163  p | _s[1];
164  p | _count;
165  }
166 
167  constexpr auto operator == (const xoroshiro128plus& rhs) noexcept -> bool {
168  return _s[0] == rhs._s[0] && _s[1] == rhs._s[1];
169  }
170 
171  constexpr auto operator != (const xoroshiro128plus& rhs) noexcept -> bool {
172  return !(*this == rhs);
173  }
174 
175  friend auto operator << (std::ostream& os, const xoroshiro128plus& rhs) -> std::ostream& {
176  os << rhs._s[0] << ' ' << rhs._s[1];
177  return os;
178  }
179 
180  friend auto operator >> (std::istream& is, xoroshiro128plus& rhs) -> std::istream& {
181  is >> rhs._s[0];
182  is >> rhs._s[1];
183  return is;
184  }
185 };
Definition: xoroshiro.h:10