/*============================================================================= Copyright (c) 2011-2019 Bolero MURAKAMI https://github.com/bolero-MURAKAMI/Sprout Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #ifndef SPROUT_RANDOM_LINEAR_FEEDBACK_SHIFT_HPP #define SPROUT_RANDOM_LINEAR_FEEDBACK_SHIFT_HPP #include #include #include #include #include #include #include #include namespace sprout { namespace random { // // linear_feedback_shift_engine // template class linear_feedback_shift_engine { public: typedef UIntType result_type; private: struct private_construct_t {}; public: SPROUT_STATIC_CONSTEXPR int word_size = w; SPROUT_STATIC_CONSTEXPR int exponent1 = k; SPROUT_STATIC_CONSTEXPR int exponent2 = q; SPROUT_STATIC_CONSTEXPR int step_size = s; SPROUT_STATIC_CONSTEXPR result_type default_seed = 341; public: static_assert(w > 0, "w > 0"); static_assert(q > 0, "q > 0"); static_assert(k < w, "k < w"); static_assert(0 < 2 * q && 2 * q < k, "0 < 2 * q && 2 * q < k"); static_assert(0 < s && s <= k - q, "0 < s && s <= k - q"); public: static SPROUT_CONSTEXPR result_type static_min() SPROUT_NOEXCEPT { return 0; } static SPROUT_CONSTEXPR result_type static_max() SPROUT_NOEXCEPT { return wordmask(); } private: static SPROUT_CONSTEXPR result_type wordmask() { return sprout::detail::low_bits_mask_t::sig_bits; } static SPROUT_CONSTEXPR result_type init_seed_1(result_type x0) { return x0 < (1 << (w - k)) ? x0 + (1 << (w - k)) : x0; } static SPROUT_CONSTEXPR result_type init_seed(result_type x0 = default_seed) { return init_seed_1(x0 & wordmask()); } template::value>::type = sprout::enabler> static SPROUT_CXX14_CONSTEXPR result_type init_seed(Sseq& seq) { return init_seed(sprout::random::detail::seed_one_int(seq)); } template::value>::type = sprout::enabler> static SPROUT_CONSTEXPR result_type init_seed(Sseq const& seq) { return init_seed(sprout::random::detail::seed_one_int(seq)); } template static SPROUT_CONSTEXPR result_type init_seed(InputIterator first, InputIterator last) { return init_seed(sprout::random::detail::get_one_int(first, last)); } private: result_type x_; private: SPROUT_CONSTEXPR linear_feedback_shift_engine(result_type x, private_construct_t) : x_(x) {} SPROUT_CONSTEXPR sprout::random::random_result generate(result_type result) const { return sprout::random::random_result( result, linear_feedback_shift_engine(result, private_construct_t()) ); } public: SPROUT_CONSTEXPR linear_feedback_shift_engine() : x_(init_seed(default_seed)) {} linear_feedback_shift_engine(linear_feedback_shift_engine const&) = default; explicit SPROUT_CONSTEXPR linear_feedback_shift_engine(result_type x0) : x_(init_seed(x0)) {} template::value>::type = sprout::enabler> explicit SPROUT_CXX14_CONSTEXPR linear_feedback_shift_engine(Sseq& seq) : x_(init_seed(seq)) {} template::value>::type = sprout::enabler> explicit SPROUT_CONSTEXPR linear_feedback_shift_engine(Sseq const& seq) : x_(init_seed(seq)) {} template SPROUT_CONSTEXPR linear_feedback_shift_engine(InputIterator first, InputIterator last) : x_(init_seed(first, last)) {} SPROUT_CXX14_CONSTEXPR void seed(result_type x0 = default_seed) { x_ = init_seed(x0); } template::value>::type = sprout::enabler> SPROUT_CXX14_CONSTEXPR void seed(Sseq& seq) { x_ = init_seed(seq); } template::value>::type = sprout::enabler> SPROUT_CXX14_CONSTEXPR void seed(Sseq const& seq) { x_ = init_seed(seq); } template SPROUT_CXX14_CONSTEXPR void seed(InputIterator first, InputIterator last) { x_ = init_seed(first, last); } SPROUT_CONSTEXPR result_type min() const SPROUT_NOEXCEPT { return static_min(); } SPROUT_CONSTEXPR result_type max() const SPROUT_NOEXCEPT { return static_max(); } SPROUT_CXX14_CONSTEXPR result_type operator()() { x_ = ((x_ & ((wordmask() << (w - k)) & wordmask())) << s) ^ ((((x_ << q) ^ x_) & wordmask()) >> (k - s)); return x_; } SPROUT_CONSTEXPR sprout::random::random_result const operator()() const { return generate(((x_ & ((wordmask() << (w - k)) & wordmask())) << s) ^ ((((x_ << q) ^ x_) & wordmask()) >> (k - s))); } friend SPROUT_CONSTEXPR bool operator==(linear_feedback_shift_engine const& lhs, linear_feedback_shift_engine const& rhs) SPROUT_NOEXCEPT { return lhs.x_ == rhs.x_; } friend SPROUT_CONSTEXPR bool operator!=(linear_feedback_shift_engine const& lhs, linear_feedback_shift_engine const& rhs) SPROUT_NOEXCEPT { return !(lhs == rhs); } template friend SPROUT_NON_CONSTEXPR std::basic_istream& operator>>( std::basic_istream& lhs, linear_feedback_shift_engine& rhs ) { return lhs >> rhs.x_; } template friend SPROUT_NON_CONSTEXPR std::basic_ostream& operator<<( std::basic_ostream& lhs, linear_feedback_shift_engine const& rhs ) { return lhs << rhs.x_; } }; template SPROUT_CONSTEXPR_OR_CONST int sprout::random::linear_feedback_shift_engine::word_size; template SPROUT_CONSTEXPR_OR_CONST int sprout::random::linear_feedback_shift_engine::exponent1; template SPROUT_CONSTEXPR_OR_CONST int sprout::random::linear_feedback_shift_engine::exponent2; template SPROUT_CONSTEXPR_OR_CONST int sprout::random::linear_feedback_shift_engine::step_size; template SPROUT_CONSTEXPR_OR_CONST UIntType sprout::random::linear_feedback_shift_engine::default_seed; } // namespace random using sprout::random::linear_feedback_shift_engine; } // namespace sprout #endif // #ifndef SPROUT_RANDOM_LINEAR_FEEDBACK_SHIFT_HPP