Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:51:10

0001 /* boost random/additive_combine.hpp header file
0002  *
0003  * Copyright Jens Maurer 2000-2001
0004  * Distributed under the Boost Software License, Version 1.0. (See
0005  * accompanying file LICENSE_1_0.txt or copy at
0006  * http://www.boost.org/LICENSE_1_0.txt)
0007  *
0008  * See http://www.boost.org for most recent version including documentation.
0009  *
0010  * $Id$
0011  *
0012  * Revision history
0013  *  2001-02-18  moved to individual header files
0014  */
0015 
0016 #ifndef BOOST_RANDOM_ADDITIVE_COMBINE_HPP
0017 #define BOOST_RANDOM_ADDITIVE_COMBINE_HPP
0018 
0019 #include <istream>
0020 #include <iosfwd>
0021 #include <algorithm> // for std::min and std::max
0022 #include <boost/config.hpp>
0023 #include <boost/cstdint.hpp>
0024 #include <boost/random/detail/config.hpp>
0025 #include <boost/random/detail/operators.hpp>
0026 #include <boost/random/detail/seed.hpp>
0027 #include <boost/random/linear_congruential.hpp>
0028 
0029 namespace boost {
0030 namespace random {
0031 
0032 /**
0033  * An instantiation of class template @c additive_combine_engine models a
0034  * \pseudo_random_number_generator. It combines two multiplicative
0035  * \linear_congruential_engine number generators, i.e. those with @c c = 0.
0036  * It is described in
0037  *
0038  *  @blockquote
0039  *  "Efficient and Portable Combined Random Number Generators", Pierre L'Ecuyer,
0040  *  Communications of the ACM, Vol. 31, No. 6, June 1988, pp. 742-749, 774
0041  *  @endblockquote
0042  *
0043  * The template parameters MLCG1 and MLCG2 shall denote two different
0044  * \linear_congruential_engine number generators, each with c = 0. Each
0045  * invocation returns a random number
0046  * X(n) := (MLCG1(n) - MLCG2(n)) mod (m1 - 1),
0047  * where m1 denotes the modulus of MLCG1. 
0048  */
0049 template<class MLCG1, class MLCG2>
0050 class additive_combine_engine
0051 {
0052 public:
0053     typedef MLCG1 first_base;
0054     typedef MLCG2 second_base;
0055     typedef typename MLCG1::result_type result_type;
0056 
0057     // Required by old Boost.Random concept
0058     BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
0059     /**
0060      * Returns the smallest value that the generator can produce
0061      */
0062     static BOOST_CONSTEXPR result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
0063     { return 1; }
0064     /**
0065      * Returns the largest value that the generator can produce
0066      */
0067     static BOOST_CONSTEXPR result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
0068     { return MLCG1::modulus-1; }
0069 
0070     /**
0071      * Constructs an @c additive_combine_engine using the
0072      * default constructors of the two base generators.
0073      */
0074     additive_combine_engine() : _mlcg1(), _mlcg2() { }
0075     /**
0076      * Constructs an @c additive_combine_engine, using seed as
0077      * the constructor argument for both base generators.
0078      */
0079     BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(additive_combine_engine,
0080         result_type, seed_arg)
0081     {
0082         _mlcg1.seed(seed_arg);
0083         _mlcg2.seed(seed_arg);
0084     }
0085     /**
0086      * Constructs an @c additive_combine_engine, using seq as
0087      * the constructor argument for both base generators.
0088      *
0089      * @xmlwarning
0090      * The semantics of this function are liable to change.
0091      * A @c seed_seq is designed to generate all the seeds
0092      * in one shot, but this seeds the two base engines
0093      * independantly and probably ends up giving the same
0094      * sequence to both.
0095      * @endxmlwarning
0096      */
0097     BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(additive_combine_engine,
0098         SeedSeq, seq)
0099     {
0100         _mlcg1.seed(seq);
0101         _mlcg2.seed(seq);
0102     }
0103     /**
0104      * Constructs an @c additive_combine_engine, using
0105      * @c seed1 and @c seed2 as the constructor argument to
0106      * the first and second base generators, respectively.
0107      */
0108     additive_combine_engine(typename MLCG1::result_type seed1, 
0109                             typename MLCG2::result_type seed2)
0110       : _mlcg1(seed1), _mlcg2(seed2) { }
0111     /**
0112      * Contructs an @c additive_combine_engine with
0113      * values from the range defined by the input iterators first
0114      * and last.  first will be modified to point to the element
0115      * after the last one used.
0116      *
0117      * Throws: @c std::invalid_argument if the input range is too small.
0118      *
0119      * Exception Safety: Basic
0120      */
0121     template<class It> additive_combine_engine(It& first, It last)
0122       : _mlcg1(first, last), _mlcg2(first, last) { }
0123 
0124     /**
0125      * Seeds an @c additive_combine_engine using the default
0126      * seeds of the two base generators.
0127      */
0128     void seed()
0129     {
0130         _mlcg1.seed();
0131         _mlcg2.seed();
0132     }
0133 
0134     /**
0135      * Seeds an @c additive_combine_engine, using @c seed as the
0136      * seed for both base generators.
0137      */
0138     BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(additive_combine_engine,
0139         result_type, seed_arg)
0140     {
0141         _mlcg1.seed(seed_arg);
0142         _mlcg2.seed(seed_arg);
0143     }
0144 
0145     /**
0146      * Seeds an @c additive_combine_engine, using @c seq to
0147      * seed both base generators.
0148      *
0149      * See the warning on the corresponding constructor.
0150      */
0151     BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(additive_combine_engine,
0152         SeedSeq, seq)
0153     {
0154         _mlcg1.seed(seq);
0155         _mlcg2.seed(seq);
0156     }
0157 
0158     /**
0159      * Seeds an @c additive_combine generator, using @c seed1 and @c seed2 as
0160      * the seeds to the first and second base generators, respectively.
0161      */
0162     void seed(typename MLCG1::result_type seed1,
0163               typename MLCG2::result_type seed2)
0164     {
0165         _mlcg1.seed(seed1);
0166         _mlcg2.seed(seed2);
0167     }
0168 
0169     /**
0170      * Seeds an @c additive_combine_engine with
0171      * values from the range defined by the input iterators first
0172      * and last.  first will be modified to point to the element
0173      * after the last one used.
0174      *
0175      * Throws: @c std::invalid_argument if the input range is too small.
0176      *
0177      * Exception Safety: Basic
0178      */
0179     template<class It> void seed(It& first, It last)
0180     {
0181         _mlcg1.seed(first, last);
0182         _mlcg2.seed(first, last);
0183     }
0184 
0185     /** Returns the next value of the generator. */
0186     result_type operator()() {
0187         result_type val1 = _mlcg1();
0188         result_type val2 = _mlcg2();
0189         if(val2 < val1) return val1 - val2;
0190         else return val1 - val2 + MLCG1::modulus - 1;
0191     }
0192   
0193     /** Fills a range with random values */
0194     template<class Iter>
0195     void generate(Iter first, Iter last)
0196     { detail::generate_from_int(*this, first, last); }
0197 
0198     /** Advances the state of the generator by @c z. */
0199     void discard(boost::uintmax_t z)
0200     {
0201         _mlcg1.discard(z);
0202         _mlcg2.discard(z);
0203     }
0204 
0205     /**
0206      * Writes the state of an @c additive_combine_engine to a @c
0207      * std::ostream.  The textual representation of an @c
0208      * additive_combine_engine is the textual representation of
0209      * the first base generator followed by the textual representation
0210      * of the second base generator.
0211      */
0212     BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, additive_combine_engine, r)
0213     { os << r._mlcg1 << ' ' << r._mlcg2; return os; }
0214 
0215     /**
0216      * Reads the state of an @c additive_combine_engine from a
0217      * @c std::istream.
0218      */
0219     BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, additive_combine_engine, r)
0220     { is >> r._mlcg1 >> std::ws >> r._mlcg2; return is; }
0221 
0222     /**
0223      * Returns: true iff the two @c additive_combine_engines will
0224      * produce the same sequence of values.
0225      */
0226     BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(additive_combine_engine, x, y)
0227     { return x._mlcg1 == y._mlcg1 && x._mlcg2 == y._mlcg2; }
0228     /**
0229      * Returns: true iff the two @c additive_combine_engines will
0230      * produce different sequences of values.
0231      */
0232     BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(additive_combine_engine)
0233 
0234 private:
0235     MLCG1 _mlcg1;
0236     MLCG2 _mlcg2;
0237 };
0238 
0239 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
0240 template<class MLCG1, class MLCG2>
0241 const bool additive_combine_engine<MLCG1, MLCG2>::has_fixed_range;
0242 #endif
0243 
0244 /// \cond show_deprecated
0245 
0246 /** Provided for backwards compatibility. */
0247 template<class MLCG1, class MLCG2, typename MLCG1::result_type val = 0>
0248 class additive_combine : public additive_combine_engine<MLCG1, MLCG2>
0249 {
0250     typedef additive_combine_engine<MLCG1, MLCG2> base_t;
0251 public:
0252     typedef typename base_t::result_type result_type;
0253     additive_combine() {}
0254     template<class T>
0255     additive_combine(T& arg) : base_t(arg) {}
0256     template<class T>
0257     additive_combine(const T& arg) : base_t(arg) {}
0258     template<class It>
0259     additive_combine(It& first, It last) : base_t(first, last) {}
0260 };
0261 
0262 /// \endcond
0263 
0264 /**
0265  * The specialization \ecuyer1988 was suggested in
0266  *
0267  *  @blockquote
0268  *  "Efficient and Portable Combined Random Number Generators", Pierre L'Ecuyer,
0269  *  Communications of the ACM, Vol. 31, No. 6, June 1988, pp. 742-749, 774
0270  *  @endblockquote
0271  */
0272 typedef additive_combine_engine<
0273     linear_congruential_engine<uint32_t, 40014, 0, 2147483563>,
0274     linear_congruential_engine<uint32_t, 40692, 0, 2147483399>
0275 > ecuyer1988;
0276 
0277 } // namespace random
0278 
0279 using random::ecuyer1988;
0280 
0281 } // namespace boost
0282 
0283 #endif // BOOST_RANDOM_ADDITIVE_COMBINE_HPP