File indexing completed on 2025-09-17 08:49:54
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_RANDOM_DETAIL_XOSHIRO_BASE
0013 #define BOOST_RANDOM_DETAIL_XOSHIRO_BASE
0014
0015 #include <boost/random/splitmix64.hpp>
0016 #include <boost/random/detail/seed.hpp>
0017 #include <boost/throw_exception.hpp>
0018 #include <boost/config.hpp>
0019 #include <array>
0020 #include <utility>
0021 #include <stdexcept>
0022 #include <limits>
0023 #include <initializer_list>
0024 #include <cstdint>
0025 #include <cstdlib>
0026 #include <string>
0027 #include <ios>
0028 #include <istream>
0029 #include <type_traits>
0030 #include <iterator>
0031
0032 namespace boost {
0033 namespace random {
0034 namespace detail {
0035
0036
0037 template <typename Derived, std::size_t N, typename OutputType = std::uint64_t, typename BlockType = std::uint64_t>
0038 class xoshiro_base
0039 {
0040 protected:
0041
0042 std::array<BlockType, N> state_;
0043
0044 private:
0045
0046 using xoshiro_type = std::integral_constant<BlockType, N>;
0047
0048 inline std::uint64_t concatenate(std::uint32_t word1, std::uint32_t word2) noexcept
0049 {
0050 return static_cast<std::uint64_t>(word1) << 32U | word2;
0051 }
0052
0053 template <typename Sseq>
0054 inline void sseq_seed_64(Sseq& seq)
0055 {
0056 for (auto& i : state_)
0057 {
0058 std::array<std::uint32_t, 2> seeds;
0059 seq.generate(seeds.begin(), seeds.end());
0060
0061 i = concatenate(seeds[0], seeds[1]);
0062 }
0063 }
0064
0065 template <typename Sseq>
0066 inline void sseq_seed_32(Sseq& seq)
0067 {
0068 seq.generate(state_.begin(), state_.end());
0069 }
0070
0071 inline void jump_impl(const std::integral_constant<std::uint64_t, 4>&) noexcept
0072 {
0073 constexpr std::array<std::uint64_t, 4U> jump = {{ UINT64_C(0x180ec6d33cfd0aba), UINT64_C(0xd5a61266f0c9392c),
0074 UINT64_C(0xa9582618e03fc9aa), UINT64_C(0x39abdc4529b1661c) }};
0075
0076 std::uint64_t s0 = 0;
0077 std::uint64_t s1 = 0;
0078 std::uint64_t s2 = 0;
0079 std::uint64_t s3 = 0;
0080
0081 for (std::uint64_t i = 0; i < jump.size(); i++)
0082 {
0083 for (std::size_t b = 0; b < 64U; b++)
0084 {
0085 if (jump[i] & UINT64_C(1) << b) {
0086 s0 ^= state_[0];
0087 s1 ^= state_[1];
0088 s2 ^= state_[2];
0089 s3 ^= state_[3];
0090 }
0091
0092 next();
0093 }
0094 }
0095
0096 state_[0] = s0;
0097 state_[1] = s1;
0098 state_[2] = s2;
0099 state_[3] = s3;
0100 }
0101
0102 inline void jump_impl(const std::integral_constant<std::uint64_t, 8>&) noexcept
0103 {
0104 constexpr std::array<std::uint64_t, 8U> jump = {{ UINT64_C(0x33ed89b6e7a353f9), UINT64_C(0x760083d7955323be),
0105 UINT64_C(0x2837f2fbb5f22fae), UINT64_C(0x4b8c5674d309511c),
0106 UINT64_C(0xb11ac47a7ba28c25), UINT64_C(0xf1be7667092bcc1c),
0107 UINT64_C(0x53851efdb6df0aaf), UINT64_C(0x1ebbc8b23eaf25db) }};
0108
0109 std::array<std::uint64_t, 8U> t = {{ 0, 0, 0, 0, 0, 0, 0, 0 }};
0110
0111 for (std::size_t i = 0; i < jump.size(); ++i)
0112 {
0113 for (std::size_t b = 0; b < 64U; ++b)
0114 {
0115 if (jump[i] & UINT64_C(1) << b)
0116 {
0117 for (std::size_t w = 0; w < state_.size(); ++w)
0118 {
0119 t[w] ^= state_[w];
0120 }
0121 }
0122
0123 next();
0124 }
0125 }
0126
0127 state_ = t;
0128 }
0129
0130 inline void long_jump_impl(const std::integral_constant<std::uint64_t, 4>&) noexcept
0131 {
0132 constexpr std::array<std::uint64_t, 4> long_jump = {{ UINT64_C(0x76e15d3efefdcbbf), UINT64_C(0xc5004e441c522fb3),
0133 UINT64_C(0x77710069854ee241), UINT64_C(0x39109bb02acbe635) }};
0134
0135 std::uint64_t s0 = 0;
0136 std::uint64_t s1 = 0;
0137 std::uint64_t s2 = 0;
0138 std::uint64_t s3 = 0;
0139
0140 for (std::size_t i = 0; i < long_jump.size(); i++)
0141 {
0142 for (std::size_t b = 0; b < 64; b++)
0143 {
0144 if (long_jump[i] & UINT64_C(1) << b)
0145 {
0146 s0 ^= state_[0];
0147 s1 ^= state_[1];
0148 s2 ^= state_[2];
0149 s3 ^= state_[3];
0150 }
0151
0152 next();
0153 }
0154 }
0155
0156 state_[0] = s0;
0157 state_[1] = s1;
0158 state_[2] = s2;
0159 state_[3] = s3;
0160 }
0161
0162 inline void long_jump_impl(const std::integral_constant<std::uint64_t, 8>&) noexcept
0163 {
0164 constexpr std::array<std::uint64_t, 8U> long_jump = {{ UINT64_C(0x11467fef8f921d28), UINT64_C(0xa2a819f2e79c8ea8),
0165 UINT64_C(0xa8299fc284b3959a), UINT64_C(0xb4d347340ca63ee1),
0166 UINT64_C(0x1cb0940bedbff6ce), UINT64_C(0xd956c5c4fa1f8e17),
0167 UINT64_C(0x915e38fd4eda93bc), UINT64_C(0x5b3ccdfa5d7daca5) }};
0168
0169 std::array<std::uint64_t, 8U> t = {{ 0, 0, 0, 0, 0, 0, 0, 0 }};
0170
0171 for (std::size_t i = 0; i < long_jump.size(); ++i)
0172 {
0173 for (std::size_t b = 0; b < 64U; ++b)
0174 {
0175 if (long_jump[i] & UINT64_C(1) << b)
0176 {
0177 for (std::size_t w = 0; w < state_.size(); ++w)
0178 {
0179 t[w] ^= state_[w];
0180 }
0181 }
0182
0183 next();
0184 }
0185 }
0186
0187 state_ = t;
0188 }
0189
0190 inline void jump_impl(const std::integral_constant<std::uint32_t, 4>&) noexcept
0191 {
0192 constexpr std::array<std::uint32_t, 4> jump = {{ UINT32_C(0x8764000b), UINT32_C(0xf542d2d3),
0193 UINT32_C(0x6fa035c3), UINT32_C(0x77f2db5b) }};
0194
0195 std::uint32_t s0 = 0;
0196 std::uint32_t s1 = 0;
0197 std::uint32_t s2 = 0;
0198 std::uint32_t s3 = 0;
0199
0200 for (std::size_t i = 0; i < jump.size(); i++)
0201 {
0202 for (std::size_t b = 0; b < 32U; b++)
0203 {
0204 if (jump[i] & UINT32_C(1) << b)
0205 {
0206 s0 ^= state_[0];
0207 s1 ^= state_[1];
0208 s2 ^= state_[2];
0209 s3 ^= state_[3];
0210 }
0211
0212 next();
0213 }
0214 }
0215
0216 state_[0] = s0;
0217 state_[1] = s1;
0218 state_[2] = s2;
0219 state_[3] = s3;
0220 }
0221
0222 inline void long_jump_impl(const std::integral_constant<std::uint32_t, 4>&) noexcept
0223 {
0224 constexpr std::array<std::uint32_t, 4> jump = {{ UINT32_C(0xb523952e), UINT32_C(0x0b6f099f),
0225 UINT32_C(0xccf5a0ef), UINT32_C(0x1c580662) }};
0226
0227 std::uint32_t s0 = 0;
0228 std::uint32_t s1 = 0;
0229 std::uint32_t s2 = 0;
0230 std::uint32_t s3 = 0;
0231
0232 for (std::size_t i = 0; i < jump.size(); i++)
0233 {
0234 for (std::size_t b = 0; b < 32; b++)
0235 {
0236 if (jump[i] & UINT32_C(1) << b)
0237 {
0238 s0 ^= state_[0];
0239 s1 ^= state_[1];
0240 s2 ^= state_[2];
0241 s3 ^= state_[3];
0242 }
0243
0244 next();
0245 }
0246 }
0247
0248 state_[0] = s0;
0249 state_[1] = s1;
0250 state_[2] = s2;
0251 state_[3] = s3;
0252 }
0253
0254 public:
0255
0256 using result_type = OutputType;
0257 using seed_type = BlockType;
0258
0259 static constexpr bool has_fixed_range {false};
0260
0261
0262 void seed()
0263 {
0264 splitmix64 gen;
0265 for (auto& i : state_)
0266 {
0267 i = static_cast<seed_type>(gen());
0268 }
0269 }
0270
0271
0272 void seed(const seed_type value)
0273 {
0274 splitmix64 gen(value);
0275 for (auto& i : state_)
0276 {
0277 i = static_cast<seed_type>(gen());
0278 }
0279 }
0280
0281
0282
0283
0284 template <typename Sseq, typename std::enable_if<!std::is_convertible<Sseq, seed_type>::value, bool>::type = true>
0285 void seed(Sseq& seq)
0286 {
0287 BOOST_IF_CONSTEXPR (std::is_same<BlockType, std::uint64_t>::value)
0288 {
0289 sseq_seed_64(seq);
0290 }
0291 else
0292 {
0293 sseq_seed_32(seq);
0294 }
0295 }
0296
0297
0298 template <typename FIter>
0299 void seed(FIter first, FIter last)
0300 {
0301 static_assert(std::is_integral<typename std::iterator_traits<FIter>::value_type>::value,
0302 "Value type must be a built-in integer type" );
0303
0304 std::size_t offset = 0;
0305 while (first != last && offset < state_.size())
0306 {
0307 state_[offset++] = static_cast<seed_type>(*first++);
0308 }
0309
0310 if (offset != state_.size())
0311 {
0312 boost::throw_exception(std::invalid_argument("Not enough elements in call to seed."));
0313 }
0314 }
0315
0316
0317
0318
0319 xoshiro_base() { seed(); }
0320
0321
0322 explicit xoshiro_base(const seed_type value)
0323 {
0324 seed(value);
0325 }
0326
0327 template <typename FIter>
0328 xoshiro_base(FIter& first, FIter last) { seed(first, last); }
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338 template <typename Sseq, typename std::enable_if<!std::is_convertible<Sseq, xoshiro_base>::value, bool>::type = true>
0339 explicit xoshiro_base(Sseq& seq)
0340 {
0341 seed(seq);
0342 }
0343
0344
0345 ~xoshiro_base() = default;
0346 xoshiro_base(const xoshiro_base& other) noexcept { state_ = other.state(); }
0347 xoshiro_base& operator=(const xoshiro_base& other) noexcept { state_ = other.state(); return *this; }
0348 xoshiro_base(xoshiro_base&& other) noexcept { state_ = other.state(); }
0349 xoshiro_base& operator=(xoshiro_base&& other) noexcept { state_ = other.state(); return *this; }
0350
0351 inline result_type next() noexcept
0352 {
0353 return static_cast<Derived*>(this)->next();
0354 }
0355
0356
0357
0358
0359 inline void jump() noexcept
0360 {
0361 jump_impl(xoshiro_type());
0362 }
0363
0364
0365
0366
0367
0368 inline void long_jump() noexcept
0369 {
0370 long_jump_impl(xoshiro_type());
0371 }
0372
0373
0374 inline result_type operator()() noexcept
0375 {
0376 return next();
0377 }
0378
0379
0380 inline void discard(const std::uint64_t z) noexcept
0381 {
0382 for (std::uint64_t i {}; i < z; ++i)
0383 {
0384 next();
0385 }
0386 }
0387
0388
0389
0390
0391
0392 inline friend bool operator==(const xoshiro_base& lhs, const xoshiro_base& rhs) noexcept
0393 {
0394 return lhs.state_ == rhs.state_;
0395 }
0396
0397
0398
0399
0400
0401 inline friend bool operator!=(const xoshiro_base& lhs, const xoshiro_base& rhs) noexcept
0402 {
0403 return lhs.state_ != rhs.state_;
0404 }
0405
0406
0407 template <typename CharT, typename Traits>
0408 inline friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
0409 const xoshiro_base& e)
0410 {
0411 for (std::size_t i {}; i < e.state_.size(); ++i)
0412 {
0413 ost << e.state_[i] << ' ';
0414 }
0415
0416 return ost;
0417 }
0418
0419
0420 template <typename CharT, typename Traits>
0421 inline friend std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
0422 xoshiro_base& e)
0423 {
0424 for (std::size_t i {}; i < e.state_.size(); ++i)
0425 {
0426 ist >> e.state_[i] >> std::ws;
0427 }
0428
0429 return ist;
0430 }
0431
0432
0433 template <typename FIter>
0434 inline void generate(FIter first, FIter last) noexcept
0435 {
0436 using iter_type = typename std::iterator_traits<FIter>::value_type;
0437
0438 while (first != last)
0439 {
0440 *first++ = static_cast<iter_type>(next());
0441 }
0442 }
0443
0444
0445
0446
0447
0448 static constexpr result_type (max)() noexcept
0449 {
0450 return (std::numeric_limits<result_type>::max)();
0451 }
0452
0453
0454
0455
0456
0457 static constexpr result_type (min)() noexcept
0458 {
0459 return (std::numeric_limits<result_type>::min)();
0460 }
0461
0462 inline std::array<BlockType, N> state() const noexcept
0463 {
0464 return state_;
0465 }
0466 };
0467
0468 }
0469 }
0470 }
0471
0472 #endif