Chris@16: /* boost random/lagged_fibonacci.hpp header file Chris@16: * Chris@16: * Copyright Jens Maurer 2000-2001 Chris@16: * Distributed under the Boost Software License, Version 1.0. (See Chris@16: * accompanying file LICENSE_1_0.txt or copy at Chris@16: * http://www.boost.org/LICENSE_1_0.txt) Chris@16: * Chris@16: * See http://www.boost.org for most recent version including documentation. Chris@16: * Chris@101: * $Id$ Chris@16: * Chris@16: * Revision history Chris@101: * 2013-10-14 fixed some warnings with Wshadow (mgaunard) Chris@16: * 2001-02-18 moved to individual header files Chris@16: */ Chris@16: Chris@16: #ifndef BOOST_RANDOM_LAGGED_FIBONACCI_HPP Chris@16: #define BOOST_RANDOM_LAGGED_FIBONACCI_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include // std::max Chris@16: #include Chris@16: #include // std::pow Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: namespace random { Chris@16: Chris@101: /** Chris@16: * Instantiations of class template \lagged_fibonacci_engine model a Chris@16: * \pseudo_random_number_generator. It uses a lagged Fibonacci Chris@16: * algorithm with two lags @c p and @c q: Chris@16: * x(i) = x(i-p) + x(i-q) (mod 2w) with p > q. Chris@16: */ Chris@16: template Chris@16: class lagged_fibonacci_engine Chris@16: { Chris@16: public: Chris@16: typedef UIntType result_type; Chris@16: BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); Chris@16: BOOST_STATIC_CONSTANT(int, word_size = w); Chris@16: BOOST_STATIC_CONSTANT(unsigned int, long_lag = p); Chris@16: BOOST_STATIC_CONSTANT(unsigned int, short_lag = q); Chris@16: Chris@16: BOOST_STATIC_CONSTANT(UIntType, default_seed = 331u); Chris@16: Chris@16: /** Returns the smallest value that the generator can produce. */ Chris@16: static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return 0; } Chris@16: /** Returns the largest value that the generator can produce. */ Chris@16: static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () Chris@16: { return low_bits_mask_t::sig_bits; } Chris@16: Chris@16: /** Creates a new @c lagged_fibonacci_engine and calls @c seed(). */ Chris@16: lagged_fibonacci_engine() { seed(); } Chris@16: Chris@16: /** Creates a new @c lagged_fibonacci_engine and calls @c seed(value). */ Chris@16: BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci_engine, Chris@16: UIntType, value) Chris@16: { seed(value); } Chris@16: Chris@16: /** Creates a new @c lagged_fibonacci_engine and calls @c seed(seq). */ Chris@16: BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(lagged_fibonacci_engine, Chris@16: SeedSeq, seq) Chris@16: { seed(seq); } Chris@16: Chris@16: /** Chris@16: * Creates a new @c lagged_fibonacci_engine and calls @c seed(first, last). Chris@16: */ Chris@16: template lagged_fibonacci_engine(It& first, It last) Chris@16: { seed(first, last); } Chris@16: Chris@16: // compiler-generated copy ctor and assignment operator are fine Chris@101: Chris@16: /** Calls @c seed(default_seed). */ Chris@16: void seed() { seed(default_seed); } Chris@16: Chris@16: /** Chris@16: * Sets the state of the generator to values produced by Chris@16: * a \minstd_rand0 generator. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(lagged_fibonacci_engine, Chris@16: UIntType, value) Chris@16: { Chris@16: minstd_rand0 intgen(static_cast(value)); Chris@16: detail::generator_seed_seq gen(intgen); Chris@16: seed(gen); Chris@16: } Chris@16: Chris@16: /** Chris@16: * Sets the state of the generator using values produced by seq. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(lagged_fibonacci_engine, SeedSeq, seq) Chris@16: { Chris@16: detail::seed_array_int(seq, x); Chris@16: i = long_lag; Chris@16: } Chris@16: Chris@16: /** Chris@16: * Sets the state of the generator to values from the iterator Chris@16: * range [first, last). If there are not enough elements in the Chris@16: * range [first, last) throws @c std::invalid_argument. Chris@16: */ Chris@16: template Chris@16: void seed(It& first, It last) Chris@16: { Chris@16: detail::fill_array_int(first, last, x); Chris@16: i = long_lag; Chris@16: } Chris@16: Chris@16: /** Returns the next value of the generator. */ Chris@16: result_type operator()() Chris@16: { Chris@16: if(i >= long_lag) Chris@16: fill(); Chris@16: return x[i++]; Chris@16: } Chris@101: Chris@16: /** Fills a range with random values */ Chris@16: template Chris@16: void generate(Iter first, Iter last) Chris@16: { detail::generate_from_int(*this, first, last); } Chris@16: Chris@16: /** Advances the state of the generator by @c z. */ Chris@16: void discard(boost::uintmax_t z) Chris@16: { Chris@16: for(boost::uintmax_t j = 0; j < z; ++j) { Chris@16: (*this)(); Chris@16: } Chris@16: } Chris@101: Chris@16: /** Chris@16: * Writes the textual representation of the generator to a @c std::ostream. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, lagged_fibonacci_engine, f) Chris@16: { Chris@16: os << f.i; Chris@101: for(unsigned int j = 0; j < f.long_lag; ++j) Chris@101: os << ' ' << f.x[j]; Chris@16: return os; Chris@16: } Chris@101: Chris@16: /** Chris@16: * Reads the textual representation of the generator from a @c std::istream. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, lagged_fibonacci_engine, f) Chris@16: { Chris@16: is >> f.i >> std::ws; Chris@101: for(unsigned int j = 0; j < f.long_lag; ++j) Chris@101: is >> f.x[j] >> std::ws; Chris@16: return is; Chris@16: } Chris@101: Chris@16: /** Chris@16: * Returns true if the two generators will produce identical Chris@16: * sequences of outputs. Chris@16: */ Chris@101: BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(lagged_fibonacci_engine, x_, y_) Chris@101: { return x_.i == y_.i && std::equal(x_.x, x_.x+long_lag, y_.x); } Chris@101: Chris@16: /** Chris@16: * Returns true if the two generators will produce different Chris@16: * sequences of outputs. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(lagged_fibonacci_engine) Chris@16: Chris@16: private: Chris@16: /// \cond show_private Chris@16: void fill(); Chris@16: /// \endcond Chris@16: Chris@16: unsigned int i; Chris@16: UIntType x[long_lag]; Chris@16: }; Chris@16: Chris@16: #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION Chris@16: // A definition is required even for integral static constants Chris@16: template Chris@16: const bool lagged_fibonacci_engine::has_fixed_range; Chris@16: template Chris@16: const unsigned int lagged_fibonacci_engine::long_lag; Chris@16: template Chris@16: const unsigned int lagged_fibonacci_engine::short_lag; Chris@16: template Chris@16: const UIntType lagged_fibonacci_engine::default_seed; Chris@16: #endif Chris@16: Chris@16: /// \cond show_private Chris@16: Chris@16: template Chris@16: void lagged_fibonacci_engine::fill() Chris@16: { Chris@16: // two loops to avoid costly modulo operations Chris@16: { // extra scope for MSVC brokenness w.r.t. for scope Chris@16: for(unsigned int j = 0; j < short_lag; ++j) Chris@16: x[j] = (x[j] + x[j+(long_lag-short_lag)]) & low_bits_mask_t::sig_bits; Chris@16: } Chris@16: for(unsigned int j = short_lag; j < long_lag; ++j) Chris@16: x[j] = (x[j] + x[j-short_lag]) & low_bits_mask_t::sig_bits; Chris@16: i = 0; Chris@16: } Chris@16: Chris@16: /// \endcond Chris@16: Chris@16: /// \cond show_deprecated Chris@16: Chris@16: // provided for backwards compatibility Chris@16: template Chris@16: class lagged_fibonacci : public lagged_fibonacci_engine Chris@16: { Chris@16: typedef lagged_fibonacci_engine base_type; Chris@16: public: Chris@16: lagged_fibonacci() {} Chris@16: BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci, UIntType, val) Chris@16: { this->seed(val); } Chris@16: BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(lagged_fibonacci, SeedSeq, seq) Chris@16: { this->seed(seq); } Chris@16: template Chris@16: lagged_fibonacci(It& first, It last) : base_type(first, last) {} Chris@16: }; Chris@16: Chris@16: /// \endcond Chris@16: Chris@16: // lagged Fibonacci generator for the range [0..1) Chris@16: // contributed by Matthias Troyer Chris@16: // for p=55, q=24 originally by G. J. Mitchell and D. P. Moore 1958 Chris@16: Chris@16: /** Chris@16: * Instantiations of class template @c lagged_fibonacci_01 model a Chris@16: * \pseudo_random_number_generator. It uses a lagged Fibonacci Chris@16: * algorithm with two lags @c p and @c q, evaluated in floating-point Chris@16: * arithmetic: x(i) = x(i-p) + x(i-q) (mod 1) with p > q. See Chris@16: * Chris@16: * @blockquote Chris@16: * "Uniform random number generators for supercomputers", Richard Brent, Chris@16: * Proc. of Fifth Australian Supercomputer Conference, Melbourne, Chris@16: * Dec. 1992, pp. 704-706. Chris@16: * @endblockquote Chris@16: * Chris@16: * @xmlnote Chris@16: * The quality of the generator crucially depends on the choice Chris@16: * of the parameters. User code should employ one of the sensibly Chris@16: * parameterized generators such as \lagged_fibonacci607 instead. Chris@16: * @endxmlnote Chris@16: * Chris@16: * The generator requires considerable amounts of memory for the storage Chris@16: * of its state array. For example, \lagged_fibonacci607 requires about Chris@16: * 4856 bytes and \lagged_fibonacci44497 requires about 350 KBytes. Chris@16: */ Chris@16: template Chris@16: class lagged_fibonacci_01_engine Chris@16: { Chris@16: public: Chris@16: typedef RealType result_type; Chris@16: BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); Chris@16: BOOST_STATIC_CONSTANT(int, word_size = w); Chris@16: BOOST_STATIC_CONSTANT(unsigned int, long_lag = p); Chris@16: BOOST_STATIC_CONSTANT(unsigned int, short_lag = q); Chris@16: Chris@16: BOOST_STATIC_CONSTANT(boost::uint32_t, default_seed = 331u); Chris@16: Chris@16: /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(). */ Chris@16: lagged_fibonacci_01_engine() { seed(); } Chris@16: /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(value). */ Chris@16: BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci_01_engine, uint32_t, value) Chris@16: { seed(value); } Chris@16: /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(gen). */ Chris@16: BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(lagged_fibonacci_01_engine, SeedSeq, seq) Chris@16: { seed(seq); } Chris@16: template lagged_fibonacci_01_engine(It& first, It last) Chris@16: { seed(first, last); } Chris@16: Chris@16: // compiler-generated copy ctor and assignment operator are fine Chris@16: Chris@16: /** Calls seed(default_seed). */ Chris@16: void seed() { seed(default_seed); } Chris@16: Chris@16: /** Chris@16: * Constructs a \minstd_rand0 generator with the constructor parameter Chris@16: * value and calls seed with it. Distinct seeds in the range Chris@16: * [1, 2147483647) will produce generators with different states. Other Chris@16: * seeds will be equivalent to some seed within this range. See Chris@16: * \linear_congruential_engine for details. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(lagged_fibonacci_01_engine, boost::uint32_t, value) Chris@16: { Chris@16: minstd_rand0 intgen(value); Chris@16: detail::generator_seed_seq gen(intgen); Chris@16: seed(gen); Chris@16: } Chris@16: Chris@16: /** Chris@16: * Seeds this @c lagged_fibonacci_01_engine using values produced by Chris@16: * @c seq.generate. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(lagged_fibonacci_01_engine, SeedSeq, seq) Chris@16: { Chris@16: detail::seed_array_real(seq, x); Chris@16: i = long_lag; Chris@16: } Chris@101: Chris@16: /** Chris@16: * Seeds this @c lagged_fibonacci_01_engine using values from the Chris@16: * iterator range [first, last). If there are not enough elements Chris@16: * in the range, throws @c std::invalid_argument. Chris@16: */ Chris@16: template Chris@16: void seed(It& first, It last) Chris@16: { Chris@16: detail::fill_array_real(first, last, x); Chris@16: i = long_lag; Chris@16: } Chris@101: Chris@16: /** Returns the smallest value that the generator can produce. */ Chris@16: static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return result_type(0); } Chris@16: /** Returns the upper bound of the generators outputs. */ Chris@16: static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () { return result_type(1); } Chris@16: Chris@16: /** Returns the next value of the generator. */ Chris@16: result_type operator()() Chris@16: { Chris@16: if(i >= long_lag) Chris@16: fill(); Chris@16: return x[i++]; Chris@16: } Chris@101: Chris@16: /** Fills a range with random values */ Chris@16: template Chris@16: void generate(Iter first, Iter last) Chris@16: { return detail::generate_from_real(*this, first, last); } Chris@16: Chris@16: /** Advances the state of the generator by @c z. */ Chris@16: void discard(boost::uintmax_t z) Chris@16: { Chris@16: for(boost::uintmax_t j = 0; j < z; ++j) { Chris@16: (*this)(); Chris@16: } Chris@16: } Chris@101: Chris@16: /** Chris@16: * Writes the textual representation of the generator to a @c std::ostream. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, lagged_fibonacci_01_engine, f) Chris@16: { Chris@16: // allow for Koenig lookup Chris@16: using std::pow; Chris@16: os << f.i; Chris@101: std::ios_base::fmtflags oldflags = os.flags(os.dec | os.fixed | os.left); Chris@101: for(unsigned int j = 0; j < f.long_lag; ++j) Chris@101: os << ' ' << f.x[j] * f.modulus(); Chris@16: os.flags(oldflags); Chris@16: return os; Chris@16: } Chris@101: Chris@16: /** Chris@16: * Reads the textual representation of the generator from a @c std::istream. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, lagged_fibonacci_01_engine, f) Chris@16: { Chris@16: is >> f.i; Chris@101: for(unsigned int j = 0; j < f.long_lag; ++j) { Chris@16: typename lagged_fibonacci_01_engine::result_type value; Chris@16: is >> std::ws >> value; Chris@101: f.x[j] = value / f.modulus(); Chris@16: } Chris@16: return is; Chris@16: } Chris@101: Chris@16: /** Chris@16: * Returns true if the two generators will produce identical Chris@16: * sequences of outputs. Chris@16: */ Chris@101: BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(lagged_fibonacci_01_engine, x_, y_) Chris@101: { return x_.i == y_.i && std::equal(x_.x, x_.x+long_lag, y_.x); } Chris@101: Chris@16: /** Chris@16: * Returns true if the two generators will produce different Chris@16: * sequences of outputs. Chris@16: */ Chris@16: BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(lagged_fibonacci_01_engine) Chris@16: Chris@16: private: Chris@16: /// \cond show_private Chris@16: void fill(); Chris@16: static RealType modulus() Chris@16: { Chris@16: using std::pow; Chris@16: return pow(RealType(2), word_size); Chris@16: } Chris@16: /// \endcond Chris@16: unsigned int i; Chris@16: RealType x[long_lag]; Chris@16: }; Chris@16: Chris@16: #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION Chris@16: // A definition is required even for integral static constants Chris@16: template Chris@16: const bool lagged_fibonacci_01_engine::has_fixed_range; Chris@16: template Chris@16: const unsigned int lagged_fibonacci_01_engine::long_lag; Chris@16: template Chris@16: const unsigned int lagged_fibonacci_01_engine::short_lag; Chris@16: template Chris@16: const int lagged_fibonacci_01_engine::word_size; Chris@16: template Chris@16: const boost::uint32_t lagged_fibonacci_01_engine::default_seed; Chris@16: #endif Chris@16: Chris@16: /// \cond show_private Chris@16: template Chris@16: void lagged_fibonacci_01_engine::fill() Chris@16: { Chris@16: // two loops to avoid costly modulo operations Chris@16: { // extra scope for MSVC brokenness w.r.t. for scope Chris@16: for(unsigned int j = 0; j < short_lag; ++j) { Chris@16: RealType t = x[j] + x[j+(long_lag-short_lag)]; Chris@16: if(t >= RealType(1)) Chris@16: t -= RealType(1); Chris@16: x[j] = t; Chris@16: } Chris@16: } Chris@16: for(unsigned int j = short_lag; j < long_lag; ++j) { Chris@16: RealType t = x[j] + x[j-short_lag]; Chris@16: if(t >= RealType(1)) Chris@16: t -= RealType(1); Chris@16: x[j] = t; Chris@16: } Chris@16: i = 0; Chris@16: } Chris@16: /// \endcond Chris@16: Chris@16: /// \cond show_deprecated Chris@16: Chris@16: // provided for backwards compatibility Chris@16: template Chris@16: class lagged_fibonacci_01 : public lagged_fibonacci_01_engine Chris@16: { Chris@16: typedef lagged_fibonacci_01_engine base_type; Chris@16: public: Chris@16: lagged_fibonacci_01() {} Chris@16: BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci_01, boost::uint32_t, val) Chris@16: { this->seed(val); } Chris@16: BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(lagged_fibonacci_01, SeedSeq, seq) Chris@16: { this->seed(seq); } Chris@16: template Chris@16: lagged_fibonacci_01(It& first, It last) : base_type(first, last) {} Chris@16: }; Chris@16: Chris@16: /// \endcond Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: template Chris@16: struct generator_bits; Chris@16: Chris@16: template Chris@16: struct generator_bits > Chris@16: { Chris@16: static std::size_t value() { return w; } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct generator_bits > Chris@16: { Chris@16: static std::size_t value() { return w; } Chris@16: }; Chris@16: Chris@16: } Chris@16: Chris@16: #ifdef BOOST_RANDOM_DOXYGEN Chris@16: namespace detail { Chris@16: /** Chris@16: * The specializations lagged_fibonacci607 ... lagged_fibonacci44497 Chris@16: * use well tested lags. Chris@16: * Chris@16: * See Chris@16: * Chris@16: * @blockquote Chris@16: * "On the Periods of Generalized Fibonacci Recurrences", Richard P. Brent Chris@16: * Computer Sciences Laboratory Australian National University, December 1992 Chris@16: * @endblockquote Chris@16: * Chris@16: * The lags used here can be found in Chris@16: * Chris@16: * @blockquote Chris@16: * "Uniform random number generators for supercomputers", Richard Brent, Chris@16: * Proc. of Fifth Australian Supercomputer Conference, Melbourne, Chris@16: * Dec. 1992, pp. 704-706. Chris@16: * @endblockquote Chris@16: */ Chris@16: struct lagged_fibonacci_doc {}; Chris@16: } Chris@16: #endif Chris@16: Chris@16: /** @copydoc boost::random::detail::lagged_fibonacci_doc */ Chris@16: typedef lagged_fibonacci_01_engine lagged_fibonacci607; Chris@16: /** @copydoc boost::random::detail::lagged_fibonacci_doc */ Chris@16: typedef lagged_fibonacci_01_engine lagged_fibonacci1279; Chris@16: /** @copydoc boost::random::detail::lagged_fibonacci_doc */ Chris@16: typedef lagged_fibonacci_01_engine lagged_fibonacci2281; Chris@16: /** @copydoc boost::random::detail::lagged_fibonacci_doc */ Chris@16: typedef lagged_fibonacci_01_engine lagged_fibonacci3217; Chris@16: /** @copydoc boost::random::detail::lagged_fibonacci_doc */ Chris@16: typedef lagged_fibonacci_01_engine lagged_fibonacci4423; Chris@16: /** @copydoc boost::random::detail::lagged_fibonacci_doc */ Chris@16: typedef lagged_fibonacci_01_engine lagged_fibonacci9689; Chris@16: /** @copydoc boost::random::detail::lagged_fibonacci_doc */ Chris@16: typedef lagged_fibonacci_01_engine lagged_fibonacci19937; Chris@16: /** @copydoc boost::random::detail::lagged_fibonacci_doc */ Chris@16: typedef lagged_fibonacci_01_engine lagged_fibonacci23209; Chris@16: /** @copydoc boost::random::detail::lagged_fibonacci_doc */ Chris@16: typedef lagged_fibonacci_01_engine lagged_fibonacci44497; Chris@16: Chris@16: } // namespace random Chris@16: Chris@16: using random::lagged_fibonacci607; Chris@16: using random::lagged_fibonacci1279; Chris@16: using random::lagged_fibonacci2281; Chris@16: using random::lagged_fibonacci3217; Chris@16: using random::lagged_fibonacci4423; Chris@16: using random::lagged_fibonacci9689; Chris@16: using random::lagged_fibonacci19937; Chris@16: using random::lagged_fibonacci23209; Chris@16: using random::lagged_fibonacci44497; Chris@16: Chris@16: } // namespace boost Chris@16: Chris@16: #endif // BOOST_RANDOM_LAGGED_FIBONACCI_HPP