1 /* boost random/additive_combine.hpp header file 2 * 3 * Copyright Jens Maurer 2000-2001 4 * Distributed under the Boost Software License, Version 1.0. (See 5 * accompanying file LICENSE_1_0.txt or copy at 6 * http://www.boost.org/LICENSE_1_0.txt) 7 * 8 * See http://www.boost.org for most recent version including documentation. 9 * 10 * $Id$ 11 * 12 * Revision history 13 * 2001-02-18 moved to individual header files 14 */ 15 16 #ifndef BOOST_RANDOM_ADDITIVE_COMBINE_HPP 17 #define BOOST_RANDOM_ADDITIVE_COMBINE_HPP 18 19 #include <istream> 20 #include <iosfwd> 21 #include <algorithm> // for std::min and std::max 22 #include <boost/config.hpp> 23 #include <boost/cstdint.hpp> 24 #include <boost/random/detail/config.hpp> 25 #include <boost/random/detail/operators.hpp> 26 #include <boost/random/detail/seed.hpp> 27 #include <boost/random/linear_congruential.hpp> 28 29 namespace boost { 30 namespace random { 31 32 /** 33 * An instantiation of class template @c additive_combine_engine models a 34 * \pseudo_random_number_generator. It combines two multiplicative 35 * \linear_congruential_engine number generators, i.e. those with @c c = 0. 36 * It is described in 37 * 38 * @blockquote 39 * "Efficient and Portable Combined Random Number Generators", Pierre L'Ecuyer, 40 * Communications of the ACM, Vol. 31, No. 6, June 1988, pp. 742-749, 774 41 * @endblockquote 42 * 43 * The template parameters MLCG1 and MLCG2 shall denote two different 44 * \linear_congruential_engine number generators, each with c = 0. Each 45 * invocation returns a random number 46 * X(n) := (MLCG1(n) - MLCG2(n)) mod (m1 - 1), 47 * where m1 denotes the modulus of MLCG1. 48 */ 49 template<class MLCG1, class MLCG2> 50 class additive_combine_engine 51 { 52 public: 53 typedef MLCG1 first_base; 54 typedef MLCG2 second_base; 55 typedef typename MLCG1::result_type result_type; 56 57 // Required by old Boost.Random concept 58 BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); 59 /** 60 * Returns the smallest value that the generator can produce 61 */ BOOST_PREVENT_MACRO_SUBSTITUTION()62 static BOOST_CONSTEXPR result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () 63 { return 1; } 64 /** 65 * Returns the largest value that the generator can produce 66 */ BOOST_PREVENT_MACRO_SUBSTITUTION()67 static BOOST_CONSTEXPR result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () 68 { return MLCG1::modulus-1; } 69 70 /** 71 * Constructs an @c additive_combine_engine using the 72 * default constructors of the two base generators. 73 */ additive_combine_engine()74 additive_combine_engine() : _mlcg1(), _mlcg2() { } 75 /** 76 * Constructs an @c additive_combine_engine, using seed as 77 * the constructor argument for both base generators. 78 */ BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(additive_combine_engine,result_type,seed_arg)79 BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(additive_combine_engine, 80 result_type, seed_arg) 81 { 82 _mlcg1.seed(seed_arg); 83 _mlcg2.seed(seed_arg); 84 } 85 /** 86 * Constructs an @c additive_combine_engine, using seq as 87 * the constructor argument for both base generators. 88 * 89 * @xmlwarning 90 * The semantics of this function are liable to change. 91 * A @c seed_seq is designed to generate all the seeds 92 * in one shot, but this seeds the two base engines 93 * independantly and probably ends up giving the same 94 * sequence to both. 95 * @endxmlwarning 96 */ BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(additive_combine_engine,SeedSeq,seq)97 BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(additive_combine_engine, 98 SeedSeq, seq) 99 { 100 _mlcg1.seed(seq); 101 _mlcg2.seed(seq); 102 } 103 /** 104 * Constructs an @c additive_combine_engine, using 105 * @c seed1 and @c seed2 as the constructor argument to 106 * the first and second base generators, respectively. 107 */ additive_combine_engine(typename MLCG1::result_type seed1,typename MLCG2::result_type seed2)108 additive_combine_engine(typename MLCG1::result_type seed1, 109 typename MLCG2::result_type seed2) 110 : _mlcg1(seed1), _mlcg2(seed2) { } 111 /** 112 * Contructs an @c additive_combine_engine with 113 * values from the range defined by the input iterators first 114 * and last. first will be modified to point to the element 115 * after the last one used. 116 * 117 * Throws: @c std::invalid_argument if the input range is too small. 118 * 119 * Exception Safety: Basic 120 */ additive_combine_engine(It & first,It last)121 template<class It> additive_combine_engine(It& first, It last) 122 : _mlcg1(first, last), _mlcg2(first, last) { } 123 124 /** 125 * Seeds an @c additive_combine_engine using the default 126 * seeds of the two base generators. 127 */ seed()128 void seed() 129 { 130 _mlcg1.seed(); 131 _mlcg2.seed(); 132 } 133 134 /** 135 * Seeds an @c additive_combine_engine, using @c seed as the 136 * seed for both base generators. 137 */ BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(additive_combine_engine,result_type,seed_arg)138 BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(additive_combine_engine, 139 result_type, seed_arg) 140 { 141 _mlcg1.seed(seed_arg); 142 _mlcg2.seed(seed_arg); 143 } 144 145 /** 146 * Seeds an @c additive_combine_engine, using @c seq to 147 * seed both base generators. 148 * 149 * See the warning on the corresponding constructor. 150 */ BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(additive_combine_engine,SeedSeq,seq)151 BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(additive_combine_engine, 152 SeedSeq, seq) 153 { 154 _mlcg1.seed(seq); 155 _mlcg2.seed(seq); 156 } 157 158 /** 159 * Seeds an @c additive_combine generator, using @c seed1 and @c seed2 as 160 * the seeds to the first and second base generators, respectively. 161 */ seed(typename MLCG1::result_type seed1,typename MLCG2::result_type seed2)162 void seed(typename MLCG1::result_type seed1, 163 typename MLCG2::result_type seed2) 164 { 165 _mlcg1.seed(seed1); 166 _mlcg2.seed(seed2); 167 } 168 169 /** 170 * Seeds an @c additive_combine_engine with 171 * values from the range defined by the input iterators first 172 * and last. first will be modified to point to the element 173 * after the last one used. 174 * 175 * Throws: @c std::invalid_argument if the input range is too small. 176 * 177 * Exception Safety: Basic 178 */ seed(It & first,It last)179 template<class It> void seed(It& first, It last) 180 { 181 _mlcg1.seed(first, last); 182 _mlcg2.seed(first, last); 183 } 184 185 /** Returns the next value of the generator. */ operator ()()186 result_type operator()() { 187 result_type val1 = _mlcg1(); 188 result_type val2 = _mlcg2(); 189 if(val2 < val1) return val1 - val2; 190 else return val1 - val2 + MLCG1::modulus - 1; 191 } 192 193 /** Fills a range with random values */ 194 template<class Iter> generate(Iter first,Iter last)195 void generate(Iter first, Iter last) 196 { detail::generate_from_int(*this, first, last); } 197 198 /** Advances the state of the generator by @c z. */ discard(boost::uintmax_t z)199 void discard(boost::uintmax_t z) 200 { 201 _mlcg1.discard(z); 202 _mlcg2.discard(z); 203 } 204 205 /** 206 * Writes the state of an @c additive_combine_engine to a @c 207 * std::ostream. The textual representation of an @c 208 * additive_combine_engine is the textual representation of 209 * the first base generator followed by the textual representation 210 * of the second base generator. 211 */ BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os,additive_combine_engine,r)212 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, additive_combine_engine, r) 213 { os << r._mlcg1 << ' ' << r._mlcg2; return os; } 214 215 /** 216 * Reads the state of an @c additive_combine_engine from a 217 * @c std::istream. 218 */ BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is,additive_combine_engine,r)219 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, additive_combine_engine, r) 220 { is >> r._mlcg1 >> std::ws >> r._mlcg2; return is; } 221 222 /** 223 * Returns: true iff the two @c additive_combine_engines will 224 * produce the same sequence of values. 225 */ BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(additive_combine_engine,x,y)226 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(additive_combine_engine, x, y) 227 { return x._mlcg1 == y._mlcg1 && x._mlcg2 == y._mlcg2; } 228 /** 229 * Returns: true iff the two @c additive_combine_engines will 230 * produce different sequences of values. 231 */ 232 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(additive_combine_engine) 233 234 private: 235 MLCG1 _mlcg1; 236 MLCG2 _mlcg2; 237 }; 238 239 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION 240 template<class MLCG1, class MLCG2> 241 const bool additive_combine_engine<MLCG1, MLCG2>::has_fixed_range; 242 #endif 243 244 /// \cond show_deprecated 245 246 /** Provided for backwards compatibility. */ 247 template<class MLCG1, class MLCG2, typename MLCG1::result_type val = 0> 248 class additive_combine : public additive_combine_engine<MLCG1, MLCG2> 249 { 250 typedef additive_combine_engine<MLCG1, MLCG2> base_t; 251 public: 252 typedef typename base_t::result_type result_type; additive_combine()253 additive_combine() {} 254 template<class T> additive_combine(T & arg)255 additive_combine(T& arg) : base_t(arg) {} 256 template<class T> additive_combine(const T & arg)257 additive_combine(const T& arg) : base_t(arg) {} 258 template<class It> additive_combine(It & first,It last)259 additive_combine(It& first, It last) : base_t(first, last) {} 260 }; 261 262 /// \endcond 263 264 /** 265 * The specialization \ecuyer1988 was suggested in 266 * 267 * @blockquote 268 * "Efficient and Portable Combined Random Number Generators", Pierre L'Ecuyer, 269 * Communications of the ACM, Vol. 31, No. 6, June 1988, pp. 742-749, 774 270 * @endblockquote 271 */ 272 typedef additive_combine_engine< 273 linear_congruential_engine<uint32_t, 40014, 0, 2147483563>, 274 linear_congruential_engine<uint32_t, 40692, 0, 2147483399> 275 > ecuyer1988; 276 277 } // namespace random 278 279 using random::ecuyer1988; 280 281 } // namespace boost 282 283 #endif // BOOST_RANDOM_ADDITIVE_COMBINE_HPP 284