diff --git a/include/boost/random/lagged_fibonacci.hpp b/include/boost/random/lagged_fibonacci.hpp index d3b6e87..4ee0714 100644 --- a/include/boost/random/lagged_fibonacci.hpp +++ b/include/boost/random/lagged_fibonacci.hpp @@ -16,289 +16,232 @@ #ifndef BOOST_RANDOM_LAGGED_FIBONACCI_HPP #define BOOST_RANDOM_LAGGED_FIBONACCI_HPP -#include -#include +#include +#include #include // std::max #include #include // std::pow #include #include #include -#include +#include #include #include #include #include -#include +#include namespace boost { namespace random { -#if BOOST_WORKAROUND(_MSC_FULL_VER, BOOST_TESTED_AT(13102292)) && BOOST_MSVC > 1300 -# define BOOST_RANDOM_EXTRACT_LF -#endif - -#if defined(__APPLE_CC__) && defined(__GNUC__) && (__GNUC__ == 3) && (__GNUC_MINOR__ <= 3) -# define BOOST_RANDOM_EXTRACT_LF -#endif - -# ifdef BOOST_RANDOM_EXTRACT_LF -namespace detail -{ - template - IStream& - extract_lagged_fibonacci_01( - IStream& is - , F const& f - , unsigned int& i - , RealType* x - , RealType modulus) - { - is >> i >> std::ws; - for(unsigned int i = 0; i < f.long_lag; ++i) - { - RealType value; - is >> value >> std::ws; - x[i] = value / modulus; - } - return is; - } - - template - IStream& - extract_lagged_fibonacci( - IStream& is - , F const& f - , unsigned int& i - , UIntType* x) - { - is >> i >> std::ws; - for(unsigned int i = 0; i < f.long_lag; ++i) - is >> x[i] >> std::ws; - return is; - } -} -# endif - /** * Instantiations of class template \lagged_fibonacci model a * \pseudo_random_number_generator. It uses a lagged Fibonacci * algorithm with two lags @c p and @c q: * x(i) = x(i-p) + x(i-q) (mod 2w) with p > q. */ -template -class lagged_fibonacci +template +class lagged_fibonacci_engine { public: - typedef UIntType result_type; - BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); - BOOST_STATIC_CONSTANT(int, word_size = w); - BOOST_STATIC_CONSTANT(unsigned int, long_lag = p); - BOOST_STATIC_CONSTANT(unsigned int, short_lag = q); + typedef UIntType result_type; + BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); + BOOST_STATIC_CONSTANT(int, word_size = w); + BOOST_STATIC_CONSTANT(unsigned int, long_lag = p); + BOOST_STATIC_CONSTANT(unsigned int, short_lag = q); - /** - * Returns: the smallest value that the generator can produce - */ - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; } - /** - * Returns: the largest value that the generator can produce - */ - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return wordmask; } + /** Returns the smallest value that the generator can produce. */ + static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return 0; } + /** Returns the largest value that the generator can produce. */ + static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () + { return low_bits_mask_t::sig_bits; } - /** - * Creates a new @c lagged_fibonacci generator and calls @c seed() - */ - lagged_fibonacci() { init_wordmask(); seed(); } - /** - * Creates a new @c lagged_fibonacci generator and calls @c seed(value) - */ - explicit lagged_fibonacci(uint32_t value) { init_wordmask(); seed(value); } - /** - * Creates a new @c lagged_fibonacci generator and calls @c seed(first, last) - */ - template lagged_fibonacci(It& first, It last) - { init_wordmask(); seed(first, last); } - // compiler-generated copy ctor and assignment operator are fine + /** Creates a new @c lagged_fibonacci_engine and calls @c seed(). */ + lagged_fibonacci_engine() { seed(); } -private: - /// \cond hide_private_members - void init_wordmask() - { - wordmask = 0; - for(int j = 0; j < w; ++j) - wordmask |= (1u << j); - } - /// \endcond + /** Creates a new @c lagged_fibonacci_engine and calls @c seed(value). */ + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci_engine, + uint32_t, value) + { seed(value); } -public: - /** - * Sets the state of the generator to values produced by - * a \minstd_rand generator. - */ - void seed(uint32_t value = 331u) - { - minstd_rand0 gen(value); - for(unsigned int j = 0; j < long_lag; ++j) - x[j] = gen() & wordmask; - i = long_lag; - } + /** Creates a new @c lagged_fibonacci_engine and calls @c seed(seq). */ + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(lagged_fibonacci_engine, + SeedSeq, seq) + { seed(seq); } - /** - * Sets the state of the generator to values from the iterator - * range [first, last). If there are not enough elements in the - * range [first, last) throws @c std::invalid_argument. - */ - template - void seed(It& first, It last) - { - // word size could be smaller than the seed values - unsigned int j; - for(j = 0; j < long_lag && first != last; ++j, ++first) - x[j] = *first & wordmask; - i = long_lag; - if(first == last && j < long_lag) - throw std::invalid_argument("lagged_fibonacci::seed"); - } + /** + * Creates a new @c lagged_fibonacci_engine and calls @c seed(first, last). + */ + template lagged_fibonacci_engine(It& first, It last) + { seed(first, last); } - /** - * Returns: the next value of the generator - */ - result_type operator()() - { - if(i >= long_lag) - fill(); - return x[i++]; - } + // compiler-generated copy ctor and assignment operator are fine + + /** Calls @c seed(331). */ + void seed() { seed(331u); } - static bool validation(result_type x) - { - return x == val; - } + /** + * Sets the state of the generator to values produced by + * a \minstd_rand0 generator. + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(lagged_fibonacci_engine, + uint32_t, value) + { + minstd_rand0 gen(value); + for(unsigned int j = 0; j < long_lag; ++j) + x[j] = gen() & low_bits_mask_t::sig_bits; + i = long_lag; + } + + /** + * Sets the state of the generator using values produced by seq. + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(lagged_fibonacci_engine, SeedSeq, seq) + { + boost::uint32_t temp[long_lag]; + seq.generate(&temp[0], &temp[0] + long_lag); + boost::uint32_t* iter = temp; + seed(iter, iter + long_lag); + } + + /** + * Sets the state of the generator to values from the iterator + * range [first, last). If there are not enough elements in the + * range [first, last) throws @c std::invalid_argument. + */ + template + void seed(It& first, It last) + { + // word size could be smaller than the seed values + unsigned int j; + for(j = 0; j < long_lag && first != last; ++j, ++first) + x[j] = *first & low_bits_mask_t::sig_bits; + i = long_lag; + if(first == last && j < long_lag) + throw std::invalid_argument("lagged_fibonacci::seed"); + } + + /** Returns the next value of the generator. */ + result_type operator()() + { + if(i >= long_lag) + fill(); + return x[i++]; + } -#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE + /** Fills a range with random values */ + template + void generate(Iter first, Iter last) + { + for(; first != last; ++first) { + *first = (*this)(); + } + } -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const lagged_fibonacci& f) - { - os << f.i << " "; - for(unsigned int i = 0; i < f.long_lag; ++i) - os << f.x[i] << " "; - return os; - } - - template - friend std::basic_istream& - operator>>(std::basic_istream& is, lagged_fibonacci& f) - { -# ifdef BOOST_RANDOM_EXTRACT_LF - return detail::extract_lagged_fibonacci(is, f, f.i, f.x); -# else - is >> f.i >> std::ws; - for(unsigned int i = 0; i < f.long_lag; ++i) - is >> f.x[i] >> std::ws; - return is; -# endif - } -#endif - - friend bool operator==(const lagged_fibonacci& x, const lagged_fibonacci& y) - { return x.i == y.i && std::equal(x.x, x.x+long_lag, y.x); } - friend bool operator!=(const lagged_fibonacci& x, - const lagged_fibonacci& y) - { return !(x == y); } -#else - // Use a member function; Streamable concept not supported. - bool operator==(const lagged_fibonacci& rhs) const - { return i == rhs.i && std::equal(x, x+long_lag, rhs.x); } - bool operator!=(const lagged_fibonacci& rhs) const - { return !(*this == rhs); } +#ifndef BOOST_NO_LONG_LONG + /** Advances the state of the generator by @c z. */ + void discard(boost::ulong_long_type z) + { + for(boost::ulong_long_type j = 0; j < z; ++j) { + (*this)(); + } + } #endif + + /** + * Writes the textual representation of the generator to a @c std::ostream. + */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, lagged_fibonacci_engine, f) + { + os << f.i << " "; + for(unsigned int i = 0; i < f.long_lag; ++i) + os << f.x[i] << " "; + return os; + } + + /** + * Reads the textual representation of the generator from a @c std::istream. + */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, lagged_fibonacci_engine, f) + { + is >> f.i >> std::ws; + for(unsigned int i = 0; i < f.long_lag; ++i) + is >> f.x[i] >> std::ws; + return is; + } + + /** + * Returns true if the two generators will produce identical + * sequences of outputs. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(lagged_fibonacci_engine, x, y) + { return x.i == y.i && std::equal(x.x, x.x+long_lag, y.x); } + + /** + * Returns true if the two generators will produce different + * sequences of outputs. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(lagged_fibonacci_engine) private: - /// \cond hide_private_members - void fill(); - /// \endcond + /// \cond hide_private_members + void fill(); + /// \endcond - UIntType wordmask; - unsigned int i; - UIntType x[long_lag]; + unsigned int i; + UIntType x[long_lag]; }; #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION // A definition is required even for integral static constants -template -const bool lagged_fibonacci::has_fixed_range; -template -const unsigned int lagged_fibonacci::long_lag; -template -const unsigned int lagged_fibonacci::short_lag; +template +const bool lagged_fibonacci_engine::has_fixed_range; +template +const unsigned int lagged_fibonacci_engine::long_lag; +template +const unsigned int lagged_fibonacci_engine::short_lag; #endif -/// \cond hide_private_members +/// \cond -template -void lagged_fibonacci::fill() +template +void lagged_fibonacci_engine::fill() { - // two loops to avoid costly modulo operations - { // extra scope for MSVC brokenness w.r.t. for scope - for(unsigned int j = 0; j < short_lag; ++j) - x[j] = (x[j] + x[j+(long_lag-short_lag)]) & wordmask; - } - for(unsigned int j = short_lag; j < long_lag; ++j) - x[j] = (x[j] + x[j-short_lag]) & wordmask; - i = 0; + // two loops to avoid costly modulo operations + { // extra scope for MSVC brokenness w.r.t. for scope + for(unsigned int j = 0; j < short_lag; ++j) + x[j] = (x[j] + x[j+(long_lag-short_lag)]) & low_bits_mask_t::sig_bits; + } + for(unsigned int j = short_lag; j < long_lag; ++j) + x[j] = (x[j] + x[j-short_lag]) & low_bits_mask_t::sig_bits; + i = 0; } +/// \endcond +/// \cond + +// provided for backwards compatibility +template +class lagged_fibonacci : public lagged_fibonacci_engine +{ + typedef lagged_fibonacci_engine base_type; +public: + lagged_fibonacci() {} + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci, uint32_t, val) + { this->seed(val); } + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(lagged_fibonacci, SeedSeq, seq) + { this->seed(seq); } + template + lagged_fibonacci(It& first, It last) : base_type(first, last) {} +}; + +/// \endcond // lagged Fibonacci generator for the range [0..1) // contributed by Matthias Troyer // for p=55, q=24 originally by G. J. Mitchell and D. P. Moore 1958 -template -struct fibonacci_validation -{ - BOOST_STATIC_CONSTANT(bool, is_specialized = false); - static T value() { return 0; } - static T tolerance() { return 0; } -}; - -#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION -// A definition is required even for integral static constants -template -const bool fibonacci_validation::is_specialized; -#endif - -#define BOOST_RANDOM_FIBONACCI_VAL(T,P,Q,V,E) \ -template<> \ -struct fibonacci_validation \ -{ \ - BOOST_STATIC_CONSTANT(bool, is_specialized = true); \ - static T value() { return V; } \ - static T tolerance() \ -{ return (std::max)(E, static_cast(5*std::numeric_limits::epsilon())); } \ -}; -// (The extra static_cast in the std::max call above is actually -// unnecessary except for HP aCC 1.30, which claims that -// numeric_limits::epsilon() doesn't actually return a double.) - -BOOST_RANDOM_FIBONACCI_VAL(double, 607, 273, 0.4293817707235914, 1e-14) -BOOST_RANDOM_FIBONACCI_VAL(double, 1279, 418, 0.9421630240437659, 1e-14) -BOOST_RANDOM_FIBONACCI_VAL(double, 2281, 1252, 0.1768114046909004, 1e-14) -BOOST_RANDOM_FIBONACCI_VAL(double, 3217, 576, 0.1956232694868209, 1e-14) -BOOST_RANDOM_FIBONACCI_VAL(double, 4423, 2098, 0.9499762202147172, 1e-14) -BOOST_RANDOM_FIBONACCI_VAL(double, 9689, 5502, 0.05737836943695162, 1e-14) -BOOST_RANDOM_FIBONACCI_VAL(double, 19937, 9842, 0.5076528587449834, 1e-14) -BOOST_RANDOM_FIBONACCI_VAL(double, 23209, 13470, 0.5414473810619185, 1e-14) -BOOST_RANDOM_FIBONACCI_VAL(double, 44497,21034, 0.254135073399297, 1e-14) - -#undef BOOST_RANDOM_FIBONACCI_VAL - -/// \endcond - /** * Instantiations of class template @c lagged_fibonacci_01 model a * \pseudo_random_number_generator. It uses a lagged Fibonacci @@ -322,216 +265,229 @@ BOOST_RANDOM_FIBONACCI_VAL(double, 44497,21034, 0.254135073399297, 1e-14) * 4856 bytes and \lagged_fibonacci44497 requires about 350 KBytes. */ template -class lagged_fibonacci_01 +class lagged_fibonacci_01_engine { public: - typedef RealType result_type; - BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); - BOOST_STATIC_CONSTANT(int, word_size = w); - BOOST_STATIC_CONSTANT(unsigned int, long_lag = p); - BOOST_STATIC_CONSTANT(unsigned int, short_lag = q); + typedef RealType result_type; + BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); + BOOST_STATIC_CONSTANT(int, word_size = w); + BOOST_STATIC_CONSTANT(unsigned int, long_lag = p); + BOOST_STATIC_CONSTANT(unsigned int, short_lag = q); - /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(). */ - lagged_fibonacci_01() { init_modulus(); seed(); } - /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(value). */ - BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci_01, uint32_t, value) - { init_modulus(); seed(value); } - /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(gen). */ - BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(lagged_fibonacci_01, Generator, gen) - { init_modulus(); seed(gen); } - template lagged_fibonacci_01(It& first, It last) - { init_modulus(); seed(first, last); } - // compiler-generated copy ctor and assignment operator are fine + /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(). */ + lagged_fibonacci_01_engine() { seed(); } + /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(value). */ + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci_01_engine, uint32_t, value) + { seed(value); } + /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(gen). */ + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(lagged_fibonacci_01_engine, SeedSeq, seq) + { seed(seq); } + template lagged_fibonacci_01_engine(It& first, It last) + { seed(first, last); } -private: - /// \cond hide_private_members - void init_modulus() - { -#ifndef BOOST_NO_STDC_NAMESPACE - // allow for Koenig lookup - using std::pow; -#endif - _modulus = pow(RealType(2), word_size); - } - /// \endcond + // compiler-generated copy ctor and assignment operator are fine -public: - /** Calls seed(331u). */ - void seed() { seed(331u); } - /** - * Constructs a \minstd_rand0 generator with the constructor parameter - * value and calls seed with it. Distinct seeds in the range - * [1, 2147483647) will produce generators with different states. Other - * seeds will be equivalent to some seed within this range. See - * \linear_congruential_engine for details. - */ - BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(lagged_fibonacci_01, uint32_t, value) - { - minstd_rand0 intgen(value); - seed(intgen); - } + /** Calls seed(331u). */ + void seed() { seed(331u); } - /** - * Sets the state of this @c lagged_fibonacci_01 to the values returned - * by p invocations of \uniform_01\()(gen). - * - * Complexity: Exactly p invocations of gen. - */ - BOOST_RANDOM_DETAIL_GENERATOR_SEED(lagged_fibonacci, Generator, gen) - { - // use pass-by-reference, but wrap argument in pass_through_engine - typedef detail::pass_through_engine ref_gen; - uniform_01 gen01 = - uniform_01(ref_gen(gen)); - // I could have used std::generate_n, but it takes "gen" by value - for(unsigned int j = 0; j < long_lag; ++j) - x[j] = gen01(); - i = long_lag; - } - - template - void seed(It& first, It last) - { -#ifndef BOOST_NO_STDC_NAMESPACE - // allow for Koenig lookup - using std::fmod; - using std::pow; -#endif - unsigned long mask = ~((~0u) << (w%32)); // now lowest w bits set - RealType two32 = pow(RealType(2), 32); - unsigned int j; - for(j = 0; j < long_lag && first != last; ++j) { - x[j] = RealType(0); - for(int k = 0; k < w/32 && first != last; ++k, ++first) - x[j] += *first / pow(two32,k+1); - if(first != last && mask != 0) { - x[j] += fmod((*first & mask) / _modulus, RealType(1)); - ++first; - } - } - i = long_lag; - if(first == last && j < long_lag) - throw std::invalid_argument("lagged_fibonacci_01::seed"); - } - - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(0); } - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(1); } - - result_type operator()() - { - if(i >= long_lag) - fill(); - return x[i++]; - } - - static bool validation(result_type x) - { - result_type v = fibonacci_validation::value(); - result_type epsilon = fibonacci_validation::tolerance(); - // std::abs is a source of trouble: sometimes, it's not overloaded - // for double, plus the usual namespace std noncompliance -> avoid it - // using std::abs; - // return abs(x - v) < 5 * epsilon - return x > v - epsilon && x < v + epsilon; - } - -#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE - -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const lagged_fibonacci_01&f) - { -#ifndef BOOST_NO_STDC_NAMESPACE - // allow for Koenig lookup - using std::pow; -#endif - os << f.i << " "; - std::ios_base::fmtflags oldflags = os.flags(os.dec | os.fixed | os.left); - for(unsigned int i = 0; i < f.long_lag; ++i) - os << f.x[i] * f._modulus << " "; - os.flags(oldflags); - return os; - } - - template - friend std::basic_istream& - operator>>(std::basic_istream& is, lagged_fibonacci_01& f) + /** + * Constructs a \minstd_rand0 generator with the constructor parameter + * value and calls seed with it. Distinct seeds in the range + * [1, 2147483647) will produce generators with different states. Other + * seeds will be equivalent to some seed within this range. See + * \linear_congruential_engine for details. + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(lagged_fibonacci_01_engine, uint32_t, value) { -# ifdef BOOST_RANDOM_EXTRACT_LF - return detail::extract_lagged_fibonacci_01(is, f, f.i, f.x, f._modulus); -# else - is >> f.i >> std::ws; + minstd_rand0 intgen(value); + uniform_01 dist; + for(unsigned j = 0; j < long_lag; ++j) + x[j] = dist(intgen); + i = long_lag; + } + + /** + * Seeds this @c lagged_fibonacci_01_engine using values produced by + * @c seq.generate. + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(lagged_fibonacci_01_engine, SeedSeq, seq) + { + static const int words = (w+31)/32 * long_lag; + boost::uint32_t buffer[words]; + seq.generate(&buffer[0], &buffer[0] + words); + boost::uint32_t* iter = buffer; + seed(iter, iter + words); + i = long_lag; + } + + /** + * Seeds this @c lagged_fibonacci_01_engine using values from the + * iterator range [first, last). If there are not enough elements + * in the range, throws @c std::invalid_argument. + */ + template + void seed(It& first, It last) + { + using std::fmod; + using std::pow; + unsigned long mask = ~((~0u) << (w%32)); // now lowest w bits set + RealType two32 = pow(RealType(2), 32); + unsigned int j; + for(j = 0; j < long_lag && first != last; ++j) { + x[j] = RealType(0); + for(int k = 0; k < w/32 && first != last; ++k, ++first) + x[j] += *first / pow(two32,k+1); + if(first != last && mask != 0) { + x[j] += fmod((*first & mask) / modulus(), RealType(1)); + ++first; + } + } + i = long_lag; + if(first == last && j < long_lag) + throw std::invalid_argument("lagged_fibonacci_01::seed"); + } + + /** Returns the smallest value that the generator can produce. */ + static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return result_type(0); } + /** Returns the upper bound of the generators outputs. */ + static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () { return result_type(1); } + + /** Returns the next value of the generator. */ + result_type operator()() + { + if(i >= long_lag) + fill(); + return x[i++]; + } + + /** Fills a range with random values */ + template + void generate(Iter first, Iter last) + { + for(; first != last; ++first) { + *first = static_cast((*this)() * modulus()); + } + } + +#ifndef BOOST_NO_LONG_LONG + /** Advances the state of the generator by @c z. */ + void discard(boost::ulong_long_type z) + { + for(boost::ulong_long_type j = 0; j < z; ++j) { + (*this)(); + } + } +#endif + + /** + * Writes the textual representation of the generator to a @c std::ostream. + */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, lagged_fibonacci_01_engine, f) + { + // allow for Koenig lookup + using std::pow; + os << f.i << " "; + std::ios_base::fmtflags oldflags = os.flags(os.dec | os.fixed | os.left); + for(unsigned int i = 0; i < f.long_lag; ++i) + os << f.x[i] * f.modulus() << " "; + os.flags(oldflags); + return os; + } + + /** + * Reads the textual representation of the generator from a @c std::istream. + */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, lagged_fibonacci_01_engine, f) + { + is >> f.i; for(unsigned int i = 0; i < f.long_lag; ++i) { - typename lagged_fibonacci_01::result_type value; - is >> value >> std::ws; - f.x[i] = value / f._modulus; + typename lagged_fibonacci_01_engine::result_type value; + is >> std::ws >> value; + f.x[i] = value / f.modulus(); } return is; -# endif } -#endif - - friend bool operator==(const lagged_fibonacci_01& x, - const lagged_fibonacci_01& y) - { return x.i == y.i && std::equal(x.x, x.x+long_lag, y.x); } - friend bool operator!=(const lagged_fibonacci_01& x, - const lagged_fibonacci_01& y) - { return !(x == y); } -#else - // Use a member function; Streamable concept not supported. - bool operator==(const lagged_fibonacci_01& rhs) const - { return i == rhs.i && std::equal(x, x+long_lag, rhs.x); } - bool operator!=(const lagged_fibonacci_01& rhs) const - { return !(*this == rhs); } -#endif + + /** + * Returns true if the two generators will produce identical + * sequences of outputs. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(lagged_fibonacci_01_engine, x, y) + { return x.i == y.i && std::equal(x.x, x.x+long_lag, y.x); } + + /** + * Returns true if the two generators will produce different + * sequences of outputs. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(lagged_fibonacci_01_engine) private: - /// \cond hide_private_members - void fill(); - /// \endcond - unsigned int i; - RealType x[long_lag]; - RealType _modulus; + /// \cond + void fill(); + static RealType modulus() + { + using std::pow; + return pow(RealType(2), word_size); + } + /// \endcond + unsigned int i; + RealType x[long_lag]; }; #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION // A definition is required even for integral static constants template -const bool lagged_fibonacci_01::has_fixed_range; +const bool lagged_fibonacci_01_engine::has_fixed_range; template -const unsigned int lagged_fibonacci_01::long_lag; +const unsigned int lagged_fibonacci_01_engine::long_lag; template -const unsigned int lagged_fibonacci_01::short_lag; +const unsigned int lagged_fibonacci_01_engine::short_lag; template -const int lagged_fibonacci_01::word_size; +const int lagged_fibonacci_01_engine::word_size; #endif -/// \cond hide_private_members +/// \cond template -void lagged_fibonacci_01::fill() +void lagged_fibonacci_01_engine::fill() { - // two loops to avoid costly modulo operations - { // extra scope for MSVC brokenness w.r.t. for scope - for(unsigned int j = 0; j < short_lag; ++j) { - RealType t = x[j] + x[j+(long_lag-short_lag)]; - if(t >= RealType(1)) - t -= RealType(1); - x[j] = t; - } - } - for(unsigned int j = short_lag; j < long_lag; ++j) { - RealType t = x[j] + x[j-short_lag]; - if(t >= RealType(1)) - t -= RealType(1); - x[j] = t; - } - i = 0; + // two loops to avoid costly modulo operations + { // extra scope for MSVC brokenness w.r.t. for scope + for(unsigned int j = 0; j < short_lag; ++j) { + RealType t = x[j] + x[j+(long_lag-short_lag)]; + if(t >= RealType(1)) + t -= RealType(1); + x[j] = t; + } + } + for(unsigned int j = short_lag; j < long_lag; ++j) { + RealType t = x[j] + x[j-short_lag]; + if(t >= RealType(1)) + t -= RealType(1); + x[j] = t; + } + i = 0; } /// \endcond -} // namespace random +/// \cond + +// provided for backwards compatibility +template +class lagged_fibonacci_01 : public lagged_fibonacci_01_engine +{ + typedef lagged_fibonacci_01_engine base_type; +public: + lagged_fibonacci_01() {} + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci_01, uint32_t, val) + { this->seed(val); } + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(lagged_fibonacci_01, SeedSeq, seq) + { this->seed(seq); } + template + lagged_fibonacci_01(It& first, It last) : base_type(first, last) {} +}; + +/// \endcond #ifdef BOOST_RANDOM_DOXYGEN namespace detail { @@ -558,47 +514,36 @@ struct lagged_fibonacci_doc {}; } #endif -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci607; -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci1279; -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci2281; -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci3217; -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci4423; -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci9689; -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci19937; -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci23209; -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci44497; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci607; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci1279; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci2281; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci3217; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci4423; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci9689; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci19937; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci23209; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci44497; +} // namespace random -// It is possible to partially specialize uniform_01<> on lagged_fibonacci_01<> -// to help the compiler generate efficient code. For GCC, this seems useless, -// because GCC optimizes (x-0)/(1-0) to (x-0). This is good enough for now. +using random::lagged_fibonacci607; +using random::lagged_fibonacci1279; +using random::lagged_fibonacci2281; +using random::lagged_fibonacci3217; +using random::lagged_fibonacci4423; +using random::lagged_fibonacci9689; +using random::lagged_fibonacci19937; +using random::lagged_fibonacci23209; +using random::lagged_fibonacci44497; } // namespace boost diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 086ea39..4dbe94e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1,5 +1,5 @@ # Copyright 2003 Jens Maurer -# Copyright 2009-2010 Steven Watanabe +# Copyright 2009-2011 Steven Watanabe # Distributed under the Boost Software License, Version 1.0. (See accompany- # ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -24,8 +24,6 @@ local all-urngs = kreutzer1986 mt11213b mt19937_64 - lagged_fibonacci - lagged_fibonacci607 ranlux3 ranlux4 ranlux3_01 @@ -45,6 +43,8 @@ for urng in $(all-urngs) run test_mt19937.cpp /boost//unit_test_framework ; run test_ecuyer1988.cpp /boost//unit_test_framework ; run test_hellekalek1995.cpp /boost//unit_test_framework ; +run test_lagged_fibonacci.cpp /boost//unit_test_framework ; +run test_lagged_fibonacci607.cpp /boost//unit_test_framework ; run test_seed_seq.cpp /boost//unit_test_framework ; diff --git a/test/test_lagged_fibonacci.cpp b/test/test_lagged_fibonacci.cpp new file mode 100644 index 0000000..a46b9a3 --- /dev/null +++ b/test/test_lagged_fibonacci.cpp @@ -0,0 +1,17 @@ +/* test_lagged_fibonacci.cpp + * + * Copyright Steven Watanabe 2011 + * 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) + * + * $Id$ + * + */ + +#include + +typedef boost::random::lagged_fibonacci_engine lagged_fibonacci; +#define BOOST_RANDOM_URNG lagged_fibonacci + +#include "test_generator.ipp" diff --git a/test/test_lagged_fibonacci607.cpp b/test/test_lagged_fibonacci607.cpp new file mode 100644 index 0000000..2196f31 --- /dev/null +++ b/test/test_lagged_fibonacci607.cpp @@ -0,0 +1,16 @@ +/* test_lagged_fibonacci607.cpp + * + * Copyright Steven Watanabe 2011 + * 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) + * + * $Id$ + * + */ + +#include + +#define BOOST_RANDOM_URNG boost::random::lagged_fibonacci607 + +#include "test_generator.ipp" diff --git a/test/validate.cpp b/test/validate.cpp index 805137f..6eca9a5 100644 --- a/test/validate.cpp +++ b/test/validate.cpp @@ -21,8 +21,9 @@ */ template -typename PRNG::result_type validation_value(PRNG rng) +typename PRNG::result_type validation_value() { + PRNG rng; for(int i = 0; i < 9999; i++) rng(); return rng(); @@ -31,56 +32,70 @@ typename PRNG::result_type validation_value(PRNG rng) int test_main(int, char*[]) { // own run - BOOST_CHECK_EQUAL(validation_value(boost::mt11213b()), 3809585648U); + BOOST_CHECK_EQUAL(validation_value(), 3809585648U); // validation by experiment from mt19937.c - BOOST_CHECK_EQUAL(validation_value(boost::mt19937()), 4123659995U); + BOOST_CHECK_EQUAL(validation_value(), 4123659995U); #if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) // validation from the C++0x draft (n3090) - BOOST_CHECK_EQUAL(validation_value(boost::mt19937_64()), UINT64_C(9981545732273789042)); + BOOST_CHECK_EQUAL(validation_value(), UINT64_C(9981545732273789042)); #endif // validation values from the publications - BOOST_CHECK_EQUAL(validation_value(boost::minstd_rand0()), 1043618065); + BOOST_CHECK_EQUAL(validation_value(), 1043618065); // validation values from the publications - BOOST_CHECK_EQUAL(validation_value(boost::minstd_rand()), 399268537); + BOOST_CHECK_EQUAL(validation_value(), 399268537); #if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) // by experiment from lrand48() - BOOST_CHECK_EQUAL(validation_value(boost::rand48()), 1993516219); + BOOST_CHECK_EQUAL(validation_value(), 1993516219); #endif // ???? - BOOST_CHECK_EQUAL(validation_value(boost::taus88()), 3535848941U); + BOOST_CHECK_EQUAL(validation_value(), 3535848941U); // ???? - BOOST_CHECK_EQUAL(validation_value(boost::ecuyer1988()), 2060321752); + BOOST_CHECK_EQUAL(validation_value(), 2060321752); // validation by experiment from Harry Erwin's generator.h (private e-mail) - BOOST_CHECK_EQUAL(validation_value(boost::kreutzer1986()), 139726); + BOOST_CHECK_EQUAL(validation_value(), 139726); // validation from the C++0x draft (n3090) - BOOST_CHECK_EQUAL(validation_value(boost::random::knuth_b()), 1112339016); + BOOST_CHECK_EQUAL(validation_value(), 1112339016); - BOOST_CHECK_CLOSE_FRACTION(validation_value(boost::lagged_fibonacci607()), 0.401269, 1e-5); + BOOST_CHECK_CLOSE_FRACTION(validation_value(), 0.401269, 1e-5); // principal operation validated with CLHEP, values by experiment - BOOST_CHECK_EQUAL(validation_value(boost::ranlux3()), 5957620); - BOOST_CHECK_EQUAL(validation_value(boost::ranlux4()), 8587295); + BOOST_CHECK_EQUAL(validation_value(), 5957620); + BOOST_CHECK_EQUAL(validation_value(), 8587295); - BOOST_CHECK_CLOSE_FRACTION(validation_value(boost::ranlux3_01()), 5957620/std::pow(2.0f,24), 1e-6); - BOOST_CHECK_CLOSE_FRACTION(validation_value(boost::ranlux4_01()), 8587295/std::pow(2.0f,24), 1e-6); + BOOST_CHECK_CLOSE_FRACTION(validation_value(), 5957620/std::pow(2.0f,24), 1e-6); + BOOST_CHECK_CLOSE_FRACTION(validation_value(), 8587295/std::pow(2.0f,24), 1e-6); - BOOST_CHECK_CLOSE_FRACTION(validation_value(boost::ranlux64_3_01()), 0.838413, 1e-6); - BOOST_CHECK_CLOSE_FRACTION(validation_value(boost::ranlux64_4_01()), 0.59839, 1e-6); + BOOST_CHECK_CLOSE_FRACTION(validation_value(), 0.838413, 1e-6); + BOOST_CHECK_CLOSE_FRACTION(validation_value(), 0.59839, 1e-6); - BOOST_CHECK_EQUAL(validation_value(boost::random::ranlux24()), 9901578); + BOOST_CHECK_EQUAL(validation_value(), 9901578); #if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) - BOOST_CHECK_EQUAL(validation_value(boost::random::ranlux48()), UINT64_C(249142670248501)); + BOOST_CHECK_EQUAL(validation_value(), UINT64_C(249142670248501)); #endif + BOOST_CHECK_CLOSE_FRACTION(validation_value(), 0.40126853196520074, 1e-14); + BOOST_CHECK_CLOSE_FRACTION(validation_value(), 0.56576990947654049, 1e-14); + BOOST_CHECK_CLOSE_FRACTION(validation_value(), 0.85870032418398168, 1e-14); + BOOST_CHECK_CLOSE_FRACTION(validation_value(), 0.29923216793615537, 1e-14); + BOOST_CHECK_CLOSE_FRACTION(validation_value(), 0.39798595467394815, 1e-14); + BOOST_CHECK_CLOSE_FRACTION(validation_value(), 0.22728966337376244, 1e-14); + + BOOST_CHECK_CLOSE_FRACTION(validation_value(), 0.21779661133680173, 1e-14); + BOOST_CHECK_CLOSE_FRACTION(validation_value(), 0.98718042717052668, 1e-14); + BOOST_CHECK_CLOSE_FRACTION(validation_value(), 0.86191789886161496, 1e-14); + + typedef boost::random::lagged_fibonacci_engine lagged_fibonacci; + BOOST_CHECK_EQUAL(validation_value(), 3543833); + return 0; }