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
VSMC_MNE() - 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
VSMC_MNE() - 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>());
155 std::numeric_limits<T>::max
VSMC_MNE() -
static_cast<T
>(Blocks)) {
156 internal::increment_block_safe<0>(
157 ctr, ctr_block, std::integral_constant<bool, 0 < Blocks>());
159 internal::increment_block<0>(
160 ctr, ctr_block, std::integral_constant<bool, 0 < Blocks>());
162 ctr = ctr_block.back();
168 template <
typename T, std::
size_t K>
170 std::array<T, K> *ctr_block, std::false_type)
172 for (std::size_t i = 0; i != n; ++i)
178 template <
typename T, std::
size_t K>
180 std::array<T, K> *ctr_block, std::true_type)
182 const std::size_t Blocks = M256I<T>::size() / K;
183 const std::size_t m = n / Blocks;
184 const std::size_t l = n % Blocks;
186 std::array<std::array<T, K>, Blocks> cb;
187 increment_block_set<0>(ctr, cb, std::true_type());
189 if (reinterpret_cast<std::uintptr_t>(ctr_block) % 32 == 0) {
190 for (std::size_t i = 0; i != m; ++i, ctr_block += Blocks)
191 c.store_a(ctr_block);
193 for (std::size_t i = 0; i != m; ++i, ctr_block += Blocks)
194 c.store_u(ctr_block);
196 for (std::size_t i = 0; i != l; ++i)
200 template <
typename T, std::
size_t K>
202 const std::array<T, K> &ctr, std::size_t n, std::array<T, K> *ctr_block)
205 std::integral_constant<
bool, M256I<T>::size() % K == 0>());
210 template <
typename T, std::
size_t K>
212 std::array<T, K> *ctr_block, std::true_type)
214 const std::size_t Blocks = M128I<T>::size() / K;
215 const std::size_t m = n / Blocks;
216 const std::size_t l = n % Blocks;
218 std::array<std::array<T, K>, Blocks> cb;
219 increment_block_set<0>(ctr, cb, std::true_type());
221 if (reinterpret_cast<std::uintptr_t>(ctr_block) % 16 == 0) {
222 for (std::size_t i = 0; i != m; ++i, ctr_block += Blocks)
223 c.store_a(ctr_block);
225 for (std::size_t i = 0; i != m; ++i, ctr_block += Blocks)
226 c.store_u(ctr_block);
228 for (std::size_t i = 0; i != l; ++i)
232 template <
typename T, std::
size_t K>
234 const std::array<T, K> &ctr, std::size_t n, std::array<T, K> *ctr_block)
237 std::integral_constant<
bool, M128I<T>::size() % K == 0>());
240 #else // VSMC_HAS_SSE2 242 template <
typename T, std::
size_t K>
244 const std::array<T, K> &ctr, std::size_t n, std::array<T, K> *ctr_block)
249 #endif // VSMC_HAS_SSE2 256 template <
typename T, std::
size_t K>
258 std::array<T, K> &ctr, std::size_t n, std::array<T, K> *ctr_block)
268 if (k < m && l < m - k) {
270 const T p =
static_cast<T
>(n);
271 for (T i = 0; i != p; ++i)
272 ctr_block[i].front() += i;
275 const T p =
static_cast<T
>(n);
276 for (T i = 0; i != p; ++i)
279 for (std::size_t i = 0; i != n; ++i) {
284 ctr = ctr_block[n - 1];
289 template <
typename Generator>
299 template <
typename SeedSeq>
317 template <
typename SeedSeq>
322 seq.generator(key_.begin(), key_.end());
351 generator_(ctr_, key_, buffer_);
355 return buffer_[index_++];
361 for (std::size_t i = 0; i != n; ++i)
367 static_cast<std::size_t
>(
reinterpret_cast<std::uintptr_t
>(r) % 32);
370 for (std::size_t i = 0; i != p; ++i)
376 const std::size_t q = generator_(ctr_, key_, n, r);
380 const std::size_t m = n / M_;
381 std::array<result_type, M_> *s =
382 reinterpret_cast<std::array<result_type, M_> *
>(r);
383 for (std::size_t i = 0; i != m; ++i)
384 generator_(ctr_, key_, s[i]);
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
VSMC_MNE();
421 return std::numeric_limits<result_type>::max
VSMC_MNE();
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 std::array<result_type, M_> buffer_;
487 Generator generator_;
493 generator_.reset(key_);
498 template <
typename Generator>
507 #endif // VSMC_RNG_COUNTER_HPP
const ctr_type & ctr() const
const key_type & key() const
friend bool operator==(const CounterEngine< Generator > &eng1, const CounterEngine< Generator > &eng2)
void increment(std::array< T, K > &ctr)
Increment a counter by one.
typename Generator::key_type key_type
typename Generator::ctr_type ctr_type
void increment_block(std::array< T, K > &, std::array< std::array< T, K >, Blocks > &, std::false_type)
Counter based RNG engine.
CounterEngine(SeedSeq &seq, typename std::enable_if< internal::is_seed_seq< SeedSeq, result_type, key_type, CounterEngine< Generator >>::value >::type *=nullptr)
void rng_rand(RNGType &rng, BernoulliDistribution< IntType > &dist, std::size_t n, IntType *r)
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)
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const CounterEngine< Generator > &eng)
typename Generator::result_type result_type
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 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 increment_single(std::array< T, K > &, std::false_type)