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