32 #ifndef VSMC_RNG_COUNTER_HPP 33 #define VSMC_RNG_COUNTER_HPP 43 template <std::
size_t,
typename T, std::
size_t K>
48 template <std::
size_t N,
typename T, std::
size_t K>
51 if (++std::get<N>(ctr) != 0)
54 increment_single<N + 1>(ctr, std::integral_constant<bool, N + 1 < K>());
61 template <
typename T, std::
size_t K>
64 internal::increment_single<0>(ctr, std::true_type());
69 template <
typename T, std::
size_t K, T NSkip>
70 inline void increment(std::array<T, K> &ctr, std::integral_constant<T, NSkip>)
72 if (ctr.front() < std::numeric_limits<T>::max() - NSkip) {
76 internal::increment_single<1>(
77 ctr, std::integral_constant<bool, 1 < K>());
83 template <
typename T, std::
size_t K>
84 inline void increment(std::array<T, K> &ctr, T nskip)
86 if (ctr.front() < std::numeric_limits<T>::max() - nskip) {
90 internal::increment_single<1>(
91 ctr, std::integral_constant<bool, 1 < K>());
98 template <std::
size_t,
typename T, std::
size_t K, std::
size_t Blocks>
100 std::array<std::array<T, K>, Blocks> &, std::false_type)
104 template <std::
size_t B,
typename T, std::
size_t K, std::
size_t Blocks>
106 std::array<std::array<T, K>, Blocks> &ctr_block, std::true_type)
108 std::get<B>(ctr_block) = ctr;
109 increment_block_set<B + 1>(
110 ctr, ctr_block, std::integral_constant<bool, B + 1 < Blocks>());
113 template <std::
size_t,
typename T, std::
size_t K, std::
size_t Blocks>
115 std::array<std::array<T, K>, Blocks> &, std::false_type)
119 template <std::
size_t B,
typename T, std::
size_t K, std::
size_t Blocks>
121 std::array<std::array<T, K>, Blocks> &ctr_block, std::true_type)
123 increment(std::get<B>(ctr_block), std::integral_constant<T, B + 1>());
124 increment_block<B + 1>(
125 ctr, ctr_block, std::integral_constant<bool, B + 1 < Blocks>());
128 template <std::
size_t,
typename T, std::
size_t K, std::
size_t Blocks>
130 std::array<std::array<T, K>, Blocks> &, std::false_type)
134 template <std::
size_t B,
typename T, std::
size_t K, std::
size_t Blocks>
136 std::array<std::array<T, K>, Blocks> &ctr_block, std::true_type)
138 std::get<B>(ctr_block).front() += B + 1;
139 increment_block_safe<B + 1>(
140 ctr, ctr_block, std::integral_constant<bool, B + 1 < Blocks>());
148 template <
typename T, std::
size_t K, std::
size_t Blocks>
150 std::array<T, K> &ctr, std::array<std::array<T, K>, Blocks> &ctr_block)
152 internal::increment_block_set<0>(
153 ctr, ctr_block, std::integral_constant<bool, 0 < Blocks>());
154 if (ctr.front() < std::numeric_limits<T>::max() -
static_cast<T
>(Blocks)) {
155 internal::increment_block_safe<0>(
156 ctr, ctr_block, std::integral_constant<bool, 0 < Blocks>());
158 internal::increment_block<0>(
159 ctr, ctr_block, std::integral_constant<bool, 0 < Blocks>());
161 ctr = ctr_block.back();
167 template <
typename T, std::
size_t K>
169 std::array<T, K> *ctr_block, std::false_type)
171 for (std::size_t i = 0; i != n; ++i)
177 template <
typename T, std::
size_t K>
179 std::array<T, K> *ctr_block, std::true_type)
182 const std::size_t m = n / Blocks;
183 const std::size_t l = n % Blocks;
185 std::array<std::array<T, K>, Blocks> cb;
186 increment_block_set<0>(ctr, cb, std::true_type());
188 if (reinterpret_cast<std::uintptr_t>(ctr_block) % 32 == 0) {
189 for (std::size_t i = 0; i != m; ++i, ctr_block += Blocks)
192 for (std::size_t i = 0; i != m; ++i, ctr_block += Blocks)
195 for (std::size_t i = 0; i != l; ++i)
199 template <
typename T, std::
size_t K>
201 const std::array<T, K> &ctr, std::size_t n, std::array<T, K> *ctr_block)
209 template <
typename T, std::
size_t K>
211 std::array<T, K> *ctr_block, std::true_type)
214 const std::size_t m = n / Blocks;
215 const std::size_t l = n % Blocks;
217 std::array<std::array<T, K>, Blocks> cb;
218 increment_block_set<0>(ctr, cb, std::true_type());
220 if (reinterpret_cast<std::uintptr_t>(ctr_block) % 16 == 0) {
221 for (std::size_t i = 0; i != m; ++i, ctr_block += Blocks)
224 for (std::size_t i = 0; i != m; ++i, ctr_block += Blocks)
227 for (std::size_t i = 0; i != l; ++i)
231 template <
typename T, std::
size_t K>
233 const std::array<T, K> &ctr, std::size_t n, std::array<T, K> *ctr_block)
239 #else // VSMC_HAS_SSE2 241 template <
typename T, std::
size_t K>
243 const std::array<T, K> &ctr, std::size_t n, std::array<T, K> *ctr_block)
248 #endif // VSMC_HAS_SSE2 255 template <
typename T, std::
size_t K>
257 std::array<T, K> &ctr, std::size_t n, std::array<T, K> *ctr_block)
267 if (k < m && l < m - k) {
269 const T p =
static_cast<T
>(n);
270 for (T i = 0; i != p; ++i)
271 ctr_block[i].front() += i;
274 const T p =
static_cast<T
>(n);
275 for (T i = 0; i != p; ++i)
278 for (std::size_t i = 0; i != n; ++i) {
283 ctr = ctr_block[n - 1];
288 template <
typename Generator>
298 template <
typename SeedSeq>
316 template <
typename SeedSeq>
321 seq.generator(key_.begin(), key_.end());
350 generator_(ctr_, key_, buffer_);
354 return buffer_[index_++];
359 const std::size_t remain = M_ - index_;
362 std::memcpy(r, buffer_.data() + index_,
sizeof(
result_type) * n);
367 std::memcpy(r, buffer_.data() + index_,
sizeof(
result_type) * remain);
372 const std::size_t k = 1024 / M_;
374 const std::size_t m = (n / M_) / k;
375 const std::size_t l = (n / M_) % k;
376 alignas(32) std::array<result_type, M_> buffer[k];
377 for (std::size_t i = 0; i != m; ++i) {
378 generator_(ctr_, key_, k, buffer);
379 std::memcpy(r, buffer,
sizeof(
result_type) * M_ * k);
383 generator_(ctr_, key_, l, buffer);
384 std::memcpy(r, buffer,
sizeof(
result_type) * M_ * l);
388 for (std::size_t i = 0; i != n; ++i)
394 std::size_t n =
static_cast<std::size_t
>(nskip);
395 if (index_ + n <= M_) {
408 increment(ctr_, static_cast<result_type>(n / M_));
416 return std::numeric_limits<result_type>::min();
421 return std::numeric_limits<result_type>::max();
427 if (eng1.buffer_ != eng2.buffer_)
429 if (eng1.ctr_ != eng2.ctr_)
431 if (eng1.key_ != eng2.key_)
433 if (eng1.index_ != eng2.index_)
441 return !(eng1 == eng2);
444 template <
typename CharT,
typename Traits>
446 std::basic_ostream<CharT, Traits> &os,
452 os << eng.buffer_ <<
' ';
453 os << eng.ctr_ <<
' ';
454 os << eng.key_ <<
' ';
460 template <
typename CharT,
typename Traits>
468 is >> std::ws >> eng_tmp.buffer_;
469 is >> std::ws >> eng_tmp.ctr_;
470 is >> std::ws >> eng_tmp.key_;
471 is >> std::ws >> eng_tmp.index_;
474 eng_tmp.generator_.reset(eng_tmp.key_);
475 eng = std::move(eng_tmp);
482 static constexpr std::size_t M_ = Generator::size();
484 alignas(32) std::array<result_type, M_> buffer_;
488 Generator generator_;
493 generator_.reset(key_);
498 template <
typename Generator>
507 #endif // VSMC_RNG_COUNTER_HPP
Using __mm256i as integer vector.
const ctr_type & ctr() const
const key_type & key() const
friend bool operator==(const CounterEngine< Generator > &eng1, const CounterEngine< Generator > &eng2)
void store_a(T *mem) const
void increment(std::array< T, K > &ctr)
Increment a counter by one.
typename Generator::key_type key_type
static constexpr std::size_t size()
typename Generator::ctr_type ctr_type
void rng_rand(RNGType &rng, BetaDistribution< RealType > &dist, std::size_t n, RealType *r)
void increment_block(std::array< T, K > &, std::array< std::array< T, K >, Blocks > &, std::false_type)
Counter based RNG engine.
void store_u(T *mem) const
CounterEngine(SeedSeq &seq, typename std::enable_if< internal::is_seed_seq< SeedSeq, result_type, key_type, CounterEngine< Generator >>::value >::type *=nullptr)
void increment_block_set(const std::array< T, K > &, std::array< std::array< T, K >, Blocks > &, std::false_type)
void operator()(std::size_t n, result_type *r)
CounterEngine(result_type s=0)
void key(const key_type &k)
static constexpr result_type max()
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const CounterEngine< Generator > &eng)
static constexpr result_type min()
typename Generator::result_type result_type
static constexpr std::size_t size()
void ctr(const ctr_type &c)
void seed(SeedSeq &seq, typename std::enable_if< internal::is_seed_seq< SeedSeq, result_type, key_type >::value >::type *=nullptr)
friend bool operator!=(const CounterEngine< Generator > &eng1, const CounterEngine< Generator > &eng2)
CounterEngine(const key_type &k)
void seed(const key_type &k)
void store_u(T *mem) const
void discard(result_type nskip)
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, CounterEngine< Generator > &eng)
void increment_block_safe(std::array< T, K > &, std::array< std::array< T, K >, Blocks > &, std::false_type)
void store_a(T *mem) const
void increment_single(std::array< T, K > &, std::false_type)