32 #ifndef VSMC_RNG_PHILOX_HPP 33 #define VSMC_RNG_PHILOX_HPP 43 #define VSMC_DEFINE_RNG_PHILOX_WEYL_CONSTANT(W, K, val) \ 44 template <typename T> \ 45 class PhiloxWeylConstant<T, K, W> \ 46 : public std::integral_constant<T, UINT##W##_C(val)> \ 48 }; // PhiloxMulConstant 50 #define VSMC_DEFINE_RNG_PHILOX_MUL_CONSTANT(W, K, I, val) \ 51 template <typename T> \ 52 class PhiloxMulConstant<T, K, I, W> \ 53 : public std::integral_constant<T, UINT##W##_C(val)> \ 55 }; // PhiloxMulConstant 59 #ifndef VSMC_RNG_PHILOX_ROUNDS 60 #define VSMC_RNG_PHILOX_ROUNDS 10 65 #ifndef VSMC_RNG_PHILOX_VECTOR_LENGTH 66 #define VSMC_RNG_PHILOX_VECTOR_LENGTH 4 75 template <typename T, std::size_t, int = std::numeric_limits<T>::digits>
84 template <typename T,
std::
size_t,
std::
size_t,
85 int =
std::numeric_limits<T>::digits>
102 template <typename T,
std::
size_t K>
107 template <std::
size_t I>
111 template <std::
size_t I>
118 template <typename T, int = std::numeric_limits<T>::digits>
121 template <
typename T>
125 static void eval(T a, T b, T &hi, T &lo)
129 std::array<T, 2> result;
133 static_cast<std::uint64_t>(a) * static_cast<std::uint64_t>(b);
134 #if VSMC_HAS_X86 // little endian 135 hi = std::get<1>(buf.result);
136 lo = std::get<0>(buf.result);
137 #else // VSMC_HAS_X86 138 hi =
static_cast<T
>(buf.prod >> 32);
139 lo =
static_cast<T
>(buf.prod);
140 #endif // VSMC_HAS_X86 144 template <
typename T>
148 static void eval(T a, T b, T &hi, T &lo)
153 #pragma GCC diagnostic push 154 #pragma GCC diagnostic ignored "-Wpedantic" 157 unsigned VSMC_INT128 prod;
158 std::array<T, 2> result;
161 buf.prod =
static_cast<unsigned VSMC_INT128
>(a) *
162 static_cast<unsigned VSMC_INT128>(b);
164 #pragma GCC diagnostic pop 167 #if VSMC_HAS_X86 // littel endia 168 hi = std::get<1>(buf.result);
169 lo = std::get<0>(buf.result);
170 #else // VSMC_HAS_X86 171 hi =
static_cast<T
>(buf.prod >> 64);
172 lo =
static_cast<T
>(buf.prod);
173 #endif // VSMC_HAS_X86 175 #elif defined(VSMC_MSVC) 177 unsigned __int64 Multiplier =
178 static_cast<unsigned __int64
>(multiplier::value);
179 unsigned __int64 Multiplicand =
static_cast<unsigned __int64
>(b);
180 unsigned __int64 hi_tmp = 0;
181 lo =
static_cast<T
>(_umul128(Multiplier, Multiplicand, &hi_tmp));
182 hi =
static_cast<T
>(hi_tmp);
184 #else // VSMC_HAS_INT128 186 const T a = multiplier::value;
187 const T lomask = (
static_cast<T
>(1) << 32) - 1;
188 const T ahi = a >> 32;
189 const T alo = a & lomask;
190 const T bhi = b >> 32;
191 const T blo = b & lomask;
192 const T ahbl = ahi * blo;
193 const T albh = alo * bhi;
194 const T ahbl_albh = ((ahbl & lomask) + (albh & lomask));
197 hi = ahi * bhi + (ahbl >> 32) + (albh >> 32);
198 hi += ahbl_albh >> 32;
199 hi += ((lo >> 32) < (ahbl_albh & lomask));
200 std::array<T, 2> hilo = {{lo, hi}};
204 #endif // VSMC_HAS_INT128 208 template <
typename T, std::size_t K, std::size_t N,
typename Constants,
213 static void eval(std::array<T, K / 2> &) {}
216 template <
typename T, std::
size_t N,
typename Constants>
219 template <std::
size_t I>
220 using weyl =
typename Constants::template weyl<I>;
223 static void eval(std::array<T, 1> &par)
225 std::get<0>(par) += weyl<0>::value;
229 template <
typename T, std::
size_t N,
typename Constants>
232 template <std::
size_t I>
233 using weyl =
typename Constants::template weyl<I>;
236 static void eval(std::array<T, 2> &par)
238 std::get<0>(par) += weyl<0>::value;
239 std::get<1>(par) += weyl<1>::value;
243 template <
typename T, std::
size_t K,
typename Constants>
247 template <std::
size_t Rp1>
248 static void eval(
const std::array<T, K / 2> &key,
249 std::array<std::array<T, K / 2>, Rp1> &par)
251 std::get<0>(par) = key;
252 eval<1>(par, std::integral_constant<bool, 1 < Rp1>());
256 template <std::
size_t, std::
size_t Rp1>
257 static void eval(std::array<std::array<T, K / 2>, Rp1> &, std::false_type)
261 template <std::
size_t N, std::
size_t Rp1>
263 std::array<std::array<T, K / 2>, Rp1> &par, std::true_type)
265 std::get<N>(par) = std::get<N - 1>(par);
267 eval<N + 1>(par, std::integral_constant<bool, N + 1 < Rp1>());
271 template <
typename T, std::
size_t K, std::
size_t N,
typename,
bool = (N > 0)>
275 template <std::
size_t Rp1>
277 std::array<T, K> &,
const std::array<std::array<T, K / 2>, Rp1> &)
282 template <
typename T, std::
size_t K, std::
size_t N,
typename Constants>
286 template <std::
size_t Rp1>
287 static void eval(std::array<T, K> &state,
288 const std::array<std::array<T, K / 2>, Rp1> &par)
290 eval<0>(state, par, std::integral_constant<bool, 1 < K>());
294 template <std::
size_t I>
295 using multiplier =
typename Constants::template multiplier<I>;
297 template <std::
size_t, std::
size_t Rp1>
298 static void eval(std::array<T, K> &,
299 const std::array<std::array<T, K / 2>, Rp1> &, std::false_type)
303 template <std::
size_t I, std::
size_t Rp1>
304 static void eval(std::array<T, K> &state,
305 const std::array<std::array<T, K / 2>, Rp1> &par, std::true_type)
307 T x = std::get<I + 1>(state) ^ std::get<I / 2>(std::get<N>(par));
309 std::get<I>(state), std::get<I + 1>(state));
310 std::get<I>(state) ^= x;
311 eval<I + 2>(state, par, std::integral_constant<bool, I + 3 < K>());
315 template <
typename T, std::
size_t K, std::
size_t N,
bool = (N > 0)>
319 static void eval(std::array<T, K> &) {}
322 template <
typename T, std::
size_t K, std::
size_t N>
326 static void eval(std::array<T, K> &state)
328 std::array<T, K> tmp;
329 eval<0>(state, tmp, std::integral_constant<bool, 0 < K>());
330 std::memcpy(state.data(), tmp.data(),
sizeof(T) * K);
334 template <std::
size_t>
336 const std::array<T, K> &, std::array<T, K> &, std::false_type)
340 template <std::
size_t I>
342 const std::array<T, K> &state, std::array<T, K> &tmp, std::true_type)
344 static constexpr std::size_t J =
347 std::get<I>(tmp) = std::get<J>(state);
348 eval<I + 1>(state, tmp, std::integral_constant<bool, I + 1 < K>());
352 template <
typename T, std::
size_t N>
356 static void eval(std::array<T, 2> &) {}
359 template <
typename T, std::
size_t N>
363 static void eval(std::array<T, 4> &state)
365 std::swap(std::get<0>(state), std::get<2>(state));
369 template <
typename T, std::
size_t N>
373 static void eval(std::array<T, 8> &state)
375 std::swap(std::get<0>(state), std::get<4>(state));
376 T x = std::get<7>(state);
377 std::get<7>(state) = std::get<5>(state);
378 std::get<5>(state) = std::get<3>(state);
379 std::get<3>(state) = std::get<1>(state);
380 std::get<1>(state) = x;
404 static_assert(std::is_unsigned<T>::value,
405 "**PhiloxGenerator** USED WITH T OTHER THAN UNSIGNED INTEGER TYPES");
407 static_assert(K != 0 && K % 2 == 0,
408 "**PhiloxGenerator** USED WITH K OTHER THAN MULTIPLES OF 2");
411 Rounds != 0,
"**PhiloxGenerator** USED WITH ROUNDS EQUAL TO ZERO");
417 static constexpr std::size_t
size() {
return sizeof(T) * K; }
421 template <
typename ResultType>
423 std::array<ResultType, size() /
sizeof(ResultType)> &buffer)
const 426 std::array<T, K> state;
428 std::array<ResultType, size() /
sizeof(ResultType)> result;
431 std::array<key_type, Rounds + 1> par;
436 generate<0>(buf.state, par, std::true_type());
440 template <
typename ResultType>
442 std::array<ResultType, size() /
sizeof(ResultType)> *buffer)
const 445 std::array<T, K> state;
447 std::array<ResultType, size() /
sizeof(ResultType)> result;
450 std::array<key_type, Rounds + 1> par;
453 for (std::size_t i = 0; i != n; ++i) {
456 generate<0>(buf.state, par, std::true_type());
457 buffer[i] = buf.result;
464 return gen1.key_ == gen2.key_;
470 return !(gen1 == gen2);
473 template <
typename CharT,
typename Traits>
475 std::basic_ostream<CharT, Traits> &os,
486 template <
typename CharT,
typename Traits>
488 std::basic_istream<CharT, Traits> &is,
495 is >> std::ws >> key;
498 gen.key_ = std::move(key);
506 template <std::
size_t>
507 void generate(std::array<T, K> &, std::array<key_type, Rounds + 1> &,
508 std::false_type)
const 512 template <std::
size_t N>
513 void generate(std::array<T, K> &state,
514 std::array<key_type, Rounds + 1> &par, std::true_type)
const 519 state, par, std::integral_constant<bool, (N < Rounds)>());
525 template <
typename ResultType,
typename T = ResultType,
534 template <
typename ResultType>
539 template <
typename ResultType>
544 template <
typename ResultType>
549 template <
typename ResultType>
594 #endif // VSMC_RNG_PHILOX_HPP
void operator()(ctr_type &ctr, std::array< ResultType, size()/sizeof(ResultType)> &buffer) const
friend bool operator!=(const PhiloxGenerator< T, K, Rounds > &gen1, const PhiloxGenerator< T, K, Rounds > &gen2)
static void eval(T a, T b, T &hi, T &lo)
static void eval(std::array< T, 2 > &)
static void eval(T a, T b, T &hi, T &lo)
void increment(std::array< T, K > &ctr)
Increment a counter by one.
static void eval(const std::array< T, K/2 > &key, std::array< std::array< T, K/2 >, Rp1 > &par)
Counter based RNG engine.
static void eval(std::array< T, K > &, const std::array< std::array< T, K/2 >, Rp1 > &)
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, PhiloxGenerator< T, K, Rounds > &gen)
#define VSMC_DEFINE_RNG_PHILOX_MUL_CONSTANT(W, K, I, val)
#define VSMC_RNG_PHILOX_VECTOR_LENGTH
PhiloxGenerator default vector length.
static void eval(std::array< T, K > &state)
friend bool operator==(const PhiloxGenerator< T, K, Rounds > &gen1, const PhiloxGenerator< T, K, Rounds > &gen2)
static void eval(std::array< T, 8 > &state)
static void eval(std::array< T, K/2 > &)
static void eval(std::array< T, K > &)
std::array< T, K > ctr_type
#define VSMC_RNG_PHILOX_ROUNDS
PhiloxGenerator default rounds.
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const PhiloxGenerator< T, K, Rounds > &gen)
#define VSMC_DEFINE_RNG_PHILOX_WEYL_CONSTANT(W, K, val)
static void eval(std::array< T, 4 > &state)
static void eval(std::array< T, 1 > &par)
void reset(const key_type &key)
Default Philox constants.
void operator()(ctr_type &ctr, std::size_t n, std::array< ResultType, size()/sizeof(ResultType)> *buffer) const
static constexpr std::size_t size()
std::array< T, K/2 > key_type
static void eval(std::array< T, 2 > &par)
void swap(StateMatrixBase< Layout, Dim, T > &state1, StateMatrixBase< Layout, Dim, T > &state2) noexcept
Swap two StateMatrixBase objects.
static void eval(std::array< T, K > &state, const std::array< std::array< T, K/2 >, Rp1 > &par)