#ifndef SPROUT_RANDOM_LINEAR_FEEDBACK_SHIFT_HPP #define SPROUT_RANDOM_LINEAR_FEEDBACK_SHIFT_HPP #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_constructor_tag {}; 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 UIntType 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"); private: static SPROUT_CONSTEXPR UIntType wordmask() { return sprout::detail::low_bits_mask_t::sig_bits; } static SPROUT_CONSTEXPR result_type static_min() { return 0; } static SPROUT_CONSTEXPR result_type static_max() { return wordmask(); } static SPROUT_CONSTEXPR UIntType init_seed_1(UIntType const& x0) { return x0 < (1 << (w - k)) ? x0 + (1 << (w - k)) : x0; } static SPROUT_CONSTEXPR UIntType init_seed(UIntType const& x0) { return init_seed_1(x0 & wordmask()); } private: UIntType x_; private: SPROUT_CONSTEXPR linear_feedback_shift_engine(UIntType const& x, private_constructor_tag) : 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_constructor_tag()) ); } public: SPROUT_CONSTEXPR linear_feedback_shift_engine() : x_(init_seed(default_seed)) {} SPROUT_CONSTEXPR explicit linear_feedback_shift_engine(UIntType const& x0) : x_(init_seed(x0)) {} SPROUT_CONSTEXPR result_type min() const { return static_min(); } SPROUT_CONSTEXPR result_type max() const { return static_max(); } SPROUT_CONSTEXPR sprout::random::random_result 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) { return lhs.x_ == rhs.x_; } friend SPROUT_CONSTEXPR bool operator!=(linear_feedback_shift_engine const& lhs, linear_feedback_shift_engine const& rhs) { return !(lhs == rhs); } template friend std::basic_istream& operator>>( std::basic_istream& lhs, linear_feedback_shift_engine& rhs ) { return lhs >> rhs.x_; } template friend std::basic_ostream& operator<<( std::basic_ostream& lhs, linear_feedback_shift_engine const& rhs ) { return lhs << rhs.x_; } }; template SPROUT_CONSTEXPR int sprout::random::linear_feedback_shift_engine::word_size; template SPROUT_CONSTEXPR int sprout::random::linear_feedback_shift_engine::exponent1; template SPROUT_CONSTEXPR int sprout::random::linear_feedback_shift_engine::exponent2; template SPROUT_CONSTEXPR int sprout::random::linear_feedback_shift_engine::step_size; template SPROUT_CONSTEXPR UIntType sprout::random::linear_feedback_shift_engine::default_seed; } // namespace random } // namespace sprout #endif // #ifndef SPROUT_RANDOM_LINEAR_FEEDBACK_SHIFT_HPP