Chris@16
|
1 /* boost random/subtract_with_carry.hpp header file
|
Chris@16
|
2 *
|
Chris@16
|
3 * Copyright Jens Maurer 2002
|
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 * 2002-03-02 created
|
Chris@16
|
14 */
|
Chris@16
|
15
|
Chris@16
|
16 #ifndef BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP
|
Chris@16
|
17 #define BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP
|
Chris@16
|
18
|
Chris@16
|
19 #include <boost/config/no_tr1/cmath.hpp> // std::pow
|
Chris@16
|
20 #include <iostream>
|
Chris@16
|
21 #include <algorithm> // std::equal
|
Chris@16
|
22 #include <stdexcept>
|
Chris@16
|
23 #include <boost/config.hpp>
|
Chris@16
|
24 #include <boost/limits.hpp>
|
Chris@16
|
25 #include <boost/cstdint.hpp>
|
Chris@16
|
26 #include <boost/static_assert.hpp>
|
Chris@16
|
27 #include <boost/integer/static_log2.hpp>
|
Chris@16
|
28 #include <boost/integer/integer_mask.hpp>
|
Chris@16
|
29 #include <boost/detail/workaround.hpp>
|
Chris@16
|
30 #include <boost/random/detail/config.hpp>
|
Chris@16
|
31 #include <boost/random/detail/seed.hpp>
|
Chris@16
|
32 #include <boost/random/detail/operators.hpp>
|
Chris@16
|
33 #include <boost/random/detail/seed_impl.hpp>
|
Chris@16
|
34 #include <boost/random/detail/generator_seed_seq.hpp>
|
Chris@16
|
35 #include <boost/random/linear_congruential.hpp>
|
Chris@16
|
36
|
Chris@16
|
37
|
Chris@16
|
38 namespace boost {
|
Chris@16
|
39 namespace random {
|
Chris@16
|
40
|
Chris@16
|
41 namespace detail {
|
Chris@16
|
42
|
Chris@16
|
43 struct subtract_with_carry_discard
|
Chris@16
|
44 {
|
Chris@16
|
45 template<class Engine>
|
Chris@16
|
46 static void apply(Engine& eng, boost::uintmax_t z)
|
Chris@16
|
47 {
|
Chris@16
|
48 typedef typename Engine::result_type IntType;
|
Chris@16
|
49 const std::size_t short_lag = Engine::short_lag;
|
Chris@16
|
50 const std::size_t long_lag = Engine::long_lag;
|
Chris@16
|
51 std::size_t k = eng.k;
|
Chris@16
|
52 IntType carry = eng.carry;
|
Chris@16
|
53 if(k != 0) {
|
Chris@16
|
54 // increment k until it becomes 0.
|
Chris@16
|
55 if(k < short_lag) {
|
Chris@16
|
56 std::size_t limit = (short_lag - k) < z?
|
Chris@16
|
57 short_lag : (k + static_cast<std::size_t>(z));
|
Chris@16
|
58 for(std::size_t j = k; j < limit; ++j) {
|
Chris@16
|
59 carry = eng.do_update(j, j + long_lag - short_lag, carry);
|
Chris@16
|
60 }
|
Chris@16
|
61 }
|
Chris@16
|
62 std::size_t limit = (long_lag - k) < z?
|
Chris@16
|
63 long_lag : (k + static_cast<std::size_t>(z));
|
Chris@16
|
64 std::size_t start = (k < short_lag ? short_lag : k);
|
Chris@16
|
65 for(std::size_t j = start; j < limit; ++j) {
|
Chris@16
|
66 carry = eng.do_update(j, j - short_lag, carry);
|
Chris@16
|
67 }
|
Chris@16
|
68 }
|
Chris@16
|
69
|
Chris@16
|
70 k = ((z % long_lag) + k) % long_lag;
|
Chris@16
|
71
|
Chris@16
|
72 if(k < z) {
|
Chris@16
|
73 // main loop: update full blocks from k = 0 to long_lag
|
Chris@16
|
74 for(std::size_t i = 0; i < (z - k) / long_lag; ++i) {
|
Chris@16
|
75 for(std::size_t j = 0; j < short_lag; ++j) {
|
Chris@16
|
76 carry = eng.do_update(j, j + long_lag - short_lag, carry);
|
Chris@16
|
77 }
|
Chris@16
|
78 for(std::size_t j = short_lag; j < long_lag; ++j) {
|
Chris@16
|
79 carry = eng.do_update(j, j - short_lag, carry);
|
Chris@16
|
80 }
|
Chris@16
|
81 }
|
Chris@16
|
82
|
Chris@16
|
83 // Update the last partial block
|
Chris@16
|
84 std::size_t limit = short_lag < k? short_lag : k;
|
Chris@16
|
85 for(std::size_t j = 0; j < limit; ++j) {
|
Chris@16
|
86 carry = eng.do_update(j, j + long_lag - short_lag, carry);
|
Chris@16
|
87 }
|
Chris@16
|
88 for(std::size_t j = short_lag; j < k; ++j) {
|
Chris@16
|
89 carry = eng.do_update(j, j - short_lag, carry);
|
Chris@16
|
90 }
|
Chris@16
|
91 }
|
Chris@16
|
92 eng.carry = carry;
|
Chris@16
|
93 eng.k = k;
|
Chris@16
|
94 }
|
Chris@16
|
95 };
|
Chris@16
|
96
|
Chris@16
|
97 }
|
Chris@16
|
98
|
Chris@16
|
99 /**
|
Chris@16
|
100 * Instantiations of @c subtract_with_carry_engine model a
|
Chris@16
|
101 * \pseudo_random_number_generator. The algorithm is
|
Chris@16
|
102 * described in
|
Chris@16
|
103 *
|
Chris@16
|
104 * @blockquote
|
Chris@16
|
105 * "A New Class of Random Number Generators", George
|
Chris@16
|
106 * Marsaglia and Arif Zaman, Annals of Applied Probability,
|
Chris@16
|
107 * Volume 1, Number 3 (1991), 462-480.
|
Chris@16
|
108 * @endblockquote
|
Chris@16
|
109 */
|
Chris@16
|
110 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
|
Chris@16
|
111 class subtract_with_carry_engine
|
Chris@16
|
112 {
|
Chris@16
|
113 public:
|
Chris@16
|
114 typedef IntType result_type;
|
Chris@16
|
115 BOOST_STATIC_CONSTANT(std::size_t, word_size = w);
|
Chris@16
|
116 BOOST_STATIC_CONSTANT(std::size_t, long_lag = r);
|
Chris@16
|
117 BOOST_STATIC_CONSTANT(std::size_t, short_lag = s);
|
Chris@16
|
118 BOOST_STATIC_CONSTANT(uint32_t, default_seed = 19780503u);
|
Chris@16
|
119
|
Chris@16
|
120 // Required by the old Boost.Random concepts
|
Chris@16
|
121 BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
|
Chris@16
|
122 // Backwards compatibility
|
Chris@16
|
123 BOOST_STATIC_CONSTANT(result_type, modulus = (result_type(1) << w));
|
Chris@16
|
124
|
Chris@16
|
125 BOOST_STATIC_ASSERT(std::numeric_limits<result_type>::is_integer);
|
Chris@16
|
126
|
Chris@16
|
127 /**
|
Chris@16
|
128 * Constructs a new @c subtract_with_carry_engine and seeds
|
Chris@16
|
129 * it with the default seed.
|
Chris@16
|
130 */
|
Chris@16
|
131 subtract_with_carry_engine() { seed(); }
|
Chris@16
|
132 /**
|
Chris@16
|
133 * Constructs a new @c subtract_with_carry_engine and seeds
|
Chris@16
|
134 * it with @c value.
|
Chris@16
|
135 */
|
Chris@16
|
136 BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry_engine,
|
Chris@16
|
137 IntType, value)
|
Chris@16
|
138 { seed(value); }
|
Chris@16
|
139 /**
|
Chris@16
|
140 * Constructs a new @c subtract_with_carry_engine and seeds
|
Chris@16
|
141 * it with values produced by @c seq.generate().
|
Chris@16
|
142 */
|
Chris@16
|
143 BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(subtract_with_carry_engine,
|
Chris@16
|
144 SeedSeq, seq)
|
Chris@16
|
145 { seed(seq); }
|
Chris@16
|
146 /**
|
Chris@16
|
147 * Constructs a new @c subtract_with_carry_engine and seeds
|
Chris@16
|
148 * it with values from a range. first is updated to point
|
Chris@16
|
149 * one past the last value consumed. If there are not
|
Chris@16
|
150 * enough elements in the range to fill the entire state of
|
Chris@16
|
151 * the generator, throws @c std::invalid_argument.
|
Chris@16
|
152 */
|
Chris@16
|
153 template<class It> subtract_with_carry_engine(It& first, It last)
|
Chris@16
|
154 { seed(first,last); }
|
Chris@16
|
155
|
Chris@16
|
156 // compiler-generated copy ctor and assignment operator are fine
|
Chris@16
|
157
|
Chris@16
|
158 /** Seeds the generator with the default seed. */
|
Chris@16
|
159 void seed() { seed(default_seed); }
|
Chris@16
|
160 BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry_engine,
|
Chris@16
|
161 IntType, value)
|
Chris@16
|
162 {
|
Chris@16
|
163 typedef linear_congruential_engine<uint32_t,40014,0,2147483563> gen_t;
|
Chris@16
|
164 gen_t intgen(static_cast<boost::uint32_t>(value == 0 ? default_seed : value));
|
Chris@16
|
165 detail::generator_seed_seq<gen_t> gen(intgen);
|
Chris@16
|
166 seed(gen);
|
Chris@16
|
167 }
|
Chris@16
|
168
|
Chris@16
|
169 /** Seeds the generator with values produced by @c seq.generate(). */
|
Chris@16
|
170 BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(subtract_with_carry, SeedSeq, seq)
|
Chris@16
|
171 {
|
Chris@16
|
172 detail::seed_array_int<w>(seq, x);
|
Chris@16
|
173 carry = (x[long_lag-1] == 0);
|
Chris@16
|
174 k = 0;
|
Chris@16
|
175 }
|
Chris@16
|
176
|
Chris@16
|
177 /**
|
Chris@16
|
178 * Seeds the generator with values from a range. Updates @c first to
|
Chris@16
|
179 * point one past the last consumed value. If the range does not
|
Chris@16
|
180 * contain enough elements to fill the entire state of the generator,
|
Chris@16
|
181 * throws @c std::invalid_argument.
|
Chris@16
|
182 */
|
Chris@16
|
183 template<class It>
|
Chris@16
|
184 void seed(It& first, It last)
|
Chris@16
|
185 {
|
Chris@16
|
186 detail::fill_array_int<w>(first, last, x);
|
Chris@16
|
187 carry = (x[long_lag-1] == 0);
|
Chris@16
|
188 k = 0;
|
Chris@16
|
189 }
|
Chris@16
|
190
|
Chris@16
|
191 /** Returns the smallest value that the generator can produce. */
|
Chris@16
|
192 static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
|
Chris@16
|
193 { return 0; }
|
Chris@16
|
194 /** Returns the largest value that the generator can produce. */
|
Chris@16
|
195 static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
|
Chris@16
|
196 { return boost::low_bits_mask_t<w>::sig_bits; }
|
Chris@16
|
197
|
Chris@16
|
198 /** Returns the next value of the generator. */
|
Chris@16
|
199 result_type operator()()
|
Chris@16
|
200 {
|
Chris@16
|
201 std::size_t short_index =
|
Chris@16
|
202 (k < short_lag)?
|
Chris@16
|
203 (k + long_lag - short_lag) :
|
Chris@16
|
204 (k - short_lag);
|
Chris@16
|
205 carry = do_update(k, short_index, carry);
|
Chris@16
|
206 IntType result = x[k];
|
Chris@16
|
207 ++k;
|
Chris@16
|
208 if(k >= long_lag)
|
Chris@16
|
209 k = 0;
|
Chris@16
|
210 return result;
|
Chris@16
|
211 }
|
Chris@16
|
212
|
Chris@16
|
213 /** Advances the state of the generator by @c z. */
|
Chris@16
|
214 void discard(boost::uintmax_t z)
|
Chris@16
|
215 {
|
Chris@16
|
216 detail::subtract_with_carry_discard::apply(*this, z);
|
Chris@16
|
217 }
|
Chris@16
|
218
|
Chris@16
|
219 /** Fills a range with random values. */
|
Chris@16
|
220 template<class It>
|
Chris@16
|
221 void generate(It first, It last)
|
Chris@16
|
222 { detail::generate_from_int(*this, first, last); }
|
Chris@16
|
223
|
Chris@16
|
224 /** Writes a @c subtract_with_carry_engine to a @c std::ostream. */
|
Chris@16
|
225 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, subtract_with_carry_engine, f)
|
Chris@16
|
226 {
|
Chris@16
|
227 for(unsigned int j = 0; j < f.long_lag; ++j)
|
Chris@16
|
228 os << f.compute(j) << ' ';
|
Chris@16
|
229 os << f.carry;
|
Chris@16
|
230 return os;
|
Chris@16
|
231 }
|
Chris@16
|
232
|
Chris@16
|
233 /** Reads a @c subtract_with_carry_engine from a @c std::istream. */
|
Chris@16
|
234 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, subtract_with_carry_engine, f)
|
Chris@16
|
235 {
|
Chris@16
|
236 for(unsigned int j = 0; j < f.long_lag; ++j)
|
Chris@16
|
237 is >> f.x[j] >> std::ws;
|
Chris@16
|
238 is >> f.carry;
|
Chris@16
|
239 f.k = 0;
|
Chris@16
|
240 return is;
|
Chris@16
|
241 }
|
Chris@16
|
242
|
Chris@16
|
243 /**
|
Chris@16
|
244 * Returns true if the two generators will produce identical
|
Chris@16
|
245 * sequences of values.
|
Chris@16
|
246 */
|
Chris@16
|
247 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(subtract_with_carry_engine, x, y)
|
Chris@16
|
248 {
|
Chris@16
|
249 for(unsigned int j = 0; j < r; ++j)
|
Chris@16
|
250 if(x.compute(j) != y.compute(j))
|
Chris@16
|
251 return false;
|
Chris@16
|
252 return true;
|
Chris@16
|
253 }
|
Chris@16
|
254
|
Chris@16
|
255 /**
|
Chris@16
|
256 * Returns true if the two generators will produce different
|
Chris@16
|
257 * sequences of values.
|
Chris@16
|
258 */
|
Chris@16
|
259 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(subtract_with_carry_engine)
|
Chris@16
|
260
|
Chris@16
|
261 private:
|
Chris@16
|
262 /// \cond show_private
|
Chris@16
|
263 // returns x(i-r+index), where index is in 0..r-1
|
Chris@16
|
264 IntType compute(unsigned int index) const
|
Chris@16
|
265 {
|
Chris@16
|
266 return x[(k+index) % long_lag];
|
Chris@16
|
267 }
|
Chris@16
|
268
|
Chris@16
|
269 friend struct detail::subtract_with_carry_discard;
|
Chris@16
|
270
|
Chris@16
|
271 IntType do_update(std::size_t current, std::size_t short_index, IntType carry)
|
Chris@16
|
272 {
|
Chris@16
|
273 IntType delta;
|
Chris@16
|
274 IntType temp = x[current] + carry;
|
Chris@16
|
275 if (x[short_index] >= temp) {
|
Chris@16
|
276 // x(n) >= 0
|
Chris@16
|
277 delta = x[short_index] - temp;
|
Chris@16
|
278 carry = 0;
|
Chris@16
|
279 } else {
|
Chris@16
|
280 // x(n) < 0
|
Chris@16
|
281 delta = modulus - temp + x[short_index];
|
Chris@16
|
282 carry = 1;
|
Chris@16
|
283 }
|
Chris@16
|
284 x[current] = delta;
|
Chris@16
|
285 return carry;
|
Chris@16
|
286 }
|
Chris@16
|
287 /// \endcond
|
Chris@16
|
288
|
Chris@16
|
289 // state representation; next output (state) is x(i)
|
Chris@16
|
290 // x[0] ... x[k] x[k+1] ... x[long_lag-1] represents
|
Chris@16
|
291 // x(i-k) ... x(i) x(i+1) ... x(i-k+long_lag-1)
|
Chris@16
|
292 // speed: base: 20-25 nsec
|
Chris@16
|
293 // ranlux_4: 230 nsec, ranlux_7: 430 nsec, ranlux_14: 810 nsec
|
Chris@16
|
294 // This state representation makes operator== and save/restore more
|
Chris@16
|
295 // difficult, because we've already computed "too much" and thus
|
Chris@16
|
296 // have to undo some steps to get at x(i-r) etc.
|
Chris@16
|
297
|
Chris@16
|
298 // state representation: next output (state) is x(i)
|
Chris@16
|
299 // x[0] ... x[k] x[k+1] ... x[long_lag-1] represents
|
Chris@16
|
300 // x(i-k) ... x(i) x(i-long_lag+1) ... x(i-k-1)
|
Chris@16
|
301 // speed: base 28 nsec
|
Chris@16
|
302 // ranlux_4: 370 nsec, ranlux_7: 688 nsec, ranlux_14: 1343 nsec
|
Chris@16
|
303 IntType x[long_lag];
|
Chris@16
|
304 std::size_t k;
|
Chris@16
|
305 IntType carry;
|
Chris@16
|
306 };
|
Chris@16
|
307
|
Chris@16
|
308 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
|
Chris@16
|
309 // A definition is required even for integral static constants
|
Chris@16
|
310 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
|
Chris@16
|
311 const bool subtract_with_carry_engine<IntType, w, s, r>::has_fixed_range;
|
Chris@16
|
312 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
|
Chris@16
|
313 const IntType subtract_with_carry_engine<IntType, w, s, r>::modulus;
|
Chris@16
|
314 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
|
Chris@16
|
315 const std::size_t subtract_with_carry_engine<IntType, w, s, r>::word_size;
|
Chris@16
|
316 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
|
Chris@16
|
317 const std::size_t subtract_with_carry_engine<IntType, w, s, r>::long_lag;
|
Chris@16
|
318 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
|
Chris@16
|
319 const std::size_t subtract_with_carry_engine<IntType, w, s, r>::short_lag;
|
Chris@16
|
320 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
|
Chris@16
|
321 const uint32_t subtract_with_carry_engine<IntType, w, s, r>::default_seed;
|
Chris@16
|
322 #endif
|
Chris@16
|
323
|
Chris@16
|
324
|
Chris@16
|
325 // use a floating-point representation to produce values in [0..1)
|
Chris@16
|
326 /**
|
Chris@16
|
327 * Instantiations of \subtract_with_carry_01_engine model a
|
Chris@16
|
328 * \pseudo_random_number_generator. The algorithm is
|
Chris@16
|
329 * described in
|
Chris@16
|
330 *
|
Chris@16
|
331 * @blockquote
|
Chris@16
|
332 * "A New Class of Random Number Generators", George
|
Chris@16
|
333 * Marsaglia and Arif Zaman, Annals of Applied Probability,
|
Chris@16
|
334 * Volume 1, Number 3 (1991), 462-480.
|
Chris@16
|
335 * @endblockquote
|
Chris@16
|
336 */
|
Chris@16
|
337 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
|
Chris@16
|
338 class subtract_with_carry_01_engine
|
Chris@16
|
339 {
|
Chris@16
|
340 public:
|
Chris@16
|
341 typedef RealType result_type;
|
Chris@16
|
342 BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
|
Chris@16
|
343 BOOST_STATIC_CONSTANT(std::size_t, word_size = w);
|
Chris@16
|
344 BOOST_STATIC_CONSTANT(std::size_t, long_lag = r);
|
Chris@16
|
345 BOOST_STATIC_CONSTANT(std::size_t, short_lag = s);
|
Chris@16
|
346 BOOST_STATIC_CONSTANT(boost::uint32_t, default_seed = 19780503u);
|
Chris@16
|
347
|
Chris@16
|
348 BOOST_STATIC_ASSERT(!std::numeric_limits<result_type>::is_integer);
|
Chris@16
|
349
|
Chris@16
|
350 /** Creates a new \subtract_with_carry_01_engine using the default seed. */
|
Chris@16
|
351 subtract_with_carry_01_engine() { init_modulus(); seed(); }
|
Chris@16
|
352 /** Creates a new subtract_with_carry_01_engine and seeds it with value. */
|
Chris@16
|
353 BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry_01_engine,
|
Chris@16
|
354 boost::uint32_t, value)
|
Chris@16
|
355 { init_modulus(); seed(value); }
|
Chris@16
|
356 /**
|
Chris@16
|
357 * Creates a new \subtract_with_carry_01_engine and seeds with values
|
Chris@16
|
358 * produced by seq.generate().
|
Chris@16
|
359 */
|
Chris@16
|
360 BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(subtract_with_carry_01_engine,
|
Chris@16
|
361 SeedSeq, seq)
|
Chris@16
|
362 { init_modulus(); seed(seq); }
|
Chris@16
|
363 /**
|
Chris@16
|
364 * Creates a new \subtract_with_carry_01_engine and seeds it with values
|
Chris@16
|
365 * from a range. Advances first to point one past the last consumed
|
Chris@16
|
366 * value. If the range does not contain enough elements to fill the
|
Chris@16
|
367 * entire state, throws @c std::invalid_argument.
|
Chris@16
|
368 */
|
Chris@16
|
369 template<class It> subtract_with_carry_01_engine(It& first, It last)
|
Chris@16
|
370 { init_modulus(); seed(first,last); }
|
Chris@16
|
371
|
Chris@16
|
372 private:
|
Chris@16
|
373 /// \cond show_private
|
Chris@16
|
374 void init_modulus()
|
Chris@16
|
375 {
|
Chris@16
|
376 #ifndef BOOST_NO_STDC_NAMESPACE
|
Chris@16
|
377 // allow for Koenig lookup
|
Chris@16
|
378 using std::pow;
|
Chris@16
|
379 #endif
|
Chris@16
|
380 _modulus = pow(RealType(2), RealType(word_size));
|
Chris@16
|
381 }
|
Chris@16
|
382 /// \endcond
|
Chris@16
|
383
|
Chris@16
|
384 public:
|
Chris@16
|
385 // compiler-generated copy ctor and assignment operator are fine
|
Chris@16
|
386
|
Chris@16
|
387 /** Seeds the generator with the default seed. */
|
Chris@16
|
388 void seed() { seed(default_seed); }
|
Chris@16
|
389
|
Chris@16
|
390 /** Seeds the generator with @c value. */
|
Chris@16
|
391 BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry_01_engine,
|
Chris@16
|
392 boost::uint32_t, value)
|
Chris@16
|
393 {
|
Chris@16
|
394 typedef linear_congruential_engine<uint32_t, 40014, 0, 2147483563> gen_t;
|
Chris@16
|
395 gen_t intgen(value == 0 ? default_seed : value);
|
Chris@16
|
396 detail::generator_seed_seq<gen_t> gen(intgen);
|
Chris@16
|
397 seed(gen);
|
Chris@16
|
398 }
|
Chris@16
|
399
|
Chris@16
|
400 /** Seeds the generator with values produced by @c seq.generate(). */
|
Chris@16
|
401 BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(subtract_with_carry_01_engine,
|
Chris@16
|
402 SeedSeq, seq)
|
Chris@16
|
403 {
|
Chris@16
|
404 detail::seed_array_real<w>(seq, x);
|
Chris@16
|
405 carry = (x[long_lag-1] ? 0 : 1 / _modulus);
|
Chris@16
|
406 k = 0;
|
Chris@16
|
407 }
|
Chris@16
|
408
|
Chris@16
|
409 /**
|
Chris@16
|
410 * Seeds the generator with values from a range. Updates first to
|
Chris@16
|
411 * point one past the last consumed element. If there are not
|
Chris@16
|
412 * enough elements in the range to fill the entire state, throws
|
Chris@16
|
413 * @c std::invalid_argument.
|
Chris@16
|
414 */
|
Chris@16
|
415 template<class It>
|
Chris@16
|
416 void seed(It& first, It last)
|
Chris@16
|
417 {
|
Chris@16
|
418 detail::fill_array_real<w>(first, last, x);
|
Chris@16
|
419 carry = (x[long_lag-1] ? 0 : 1 / _modulus);
|
Chris@16
|
420 k = 0;
|
Chris@16
|
421 }
|
Chris@16
|
422
|
Chris@16
|
423 /** Returns the smallest value that the generator can produce. */
|
Chris@16
|
424 static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
|
Chris@16
|
425 { return result_type(0); }
|
Chris@16
|
426 /** Returns the largest value that the generator can produce. */
|
Chris@16
|
427 static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
|
Chris@16
|
428 { return result_type(1); }
|
Chris@16
|
429
|
Chris@16
|
430 /** Returns the next value of the generator. */
|
Chris@16
|
431 result_type operator()()
|
Chris@16
|
432 {
|
Chris@16
|
433 std::size_t short_index =
|
Chris@16
|
434 (k < short_lag) ?
|
Chris@16
|
435 (k + long_lag - short_lag) :
|
Chris@16
|
436 (k - short_lag);
|
Chris@16
|
437 carry = do_update(k, short_index, carry);
|
Chris@16
|
438 RealType result = x[k];
|
Chris@16
|
439 ++k;
|
Chris@16
|
440 if(k >= long_lag)
|
Chris@16
|
441 k = 0;
|
Chris@16
|
442 return result;
|
Chris@16
|
443 }
|
Chris@16
|
444
|
Chris@16
|
445 /** Advances the state of the generator by @c z. */
|
Chris@16
|
446 void discard(boost::uintmax_t z)
|
Chris@16
|
447 { detail::subtract_with_carry_discard::apply(*this, z); }
|
Chris@16
|
448
|
Chris@16
|
449 /** Fills a range with random values. */
|
Chris@16
|
450 template<class Iter>
|
Chris@16
|
451 void generate(Iter first, Iter last)
|
Chris@16
|
452 { detail::generate_from_real(*this, first, last); }
|
Chris@16
|
453
|
Chris@16
|
454 /** Writes a \subtract_with_carry_01_engine to a @c std::ostream. */
|
Chris@16
|
455 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, subtract_with_carry_01_engine, f)
|
Chris@16
|
456 {
|
Chris@16
|
457 std::ios_base::fmtflags oldflags =
|
Chris@16
|
458 os.flags(os.dec | os.fixed | os.left);
|
Chris@16
|
459 for(unsigned int j = 0; j < f.long_lag; ++j)
|
Chris@16
|
460 os << (f.compute(j) * f._modulus) << ' ';
|
Chris@16
|
461 os << (f.carry * f._modulus);
|
Chris@16
|
462 os.flags(oldflags);
|
Chris@16
|
463 return os;
|
Chris@16
|
464 }
|
Chris@16
|
465
|
Chris@16
|
466 /** Reads a \subtract_with_carry_01_engine from a @c std::istream. */
|
Chris@16
|
467 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, subtract_with_carry_01_engine, f)
|
Chris@16
|
468 {
|
Chris@16
|
469 RealType value;
|
Chris@16
|
470 for(unsigned int j = 0; j < long_lag; ++j) {
|
Chris@16
|
471 is >> value >> std::ws;
|
Chris@16
|
472 f.x[j] = value / f._modulus;
|
Chris@16
|
473 }
|
Chris@16
|
474 is >> value;
|
Chris@16
|
475 f.carry = value / f._modulus;
|
Chris@16
|
476 f.k = 0;
|
Chris@16
|
477 return is;
|
Chris@16
|
478 }
|
Chris@16
|
479
|
Chris@16
|
480 /** Returns true if the two generators will produce identical sequences. */
|
Chris@16
|
481 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(subtract_with_carry_01_engine, x, y)
|
Chris@16
|
482 {
|
Chris@16
|
483 for(unsigned int j = 0; j < r; ++j)
|
Chris@16
|
484 if(x.compute(j) != y.compute(j))
|
Chris@16
|
485 return false;
|
Chris@16
|
486 return true;
|
Chris@16
|
487 }
|
Chris@16
|
488
|
Chris@16
|
489 /** Returns true if the two generators will produce different sequences. */
|
Chris@16
|
490 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(subtract_with_carry_01_engine)
|
Chris@16
|
491
|
Chris@16
|
492 private:
|
Chris@16
|
493 /// \cond show_private
|
Chris@16
|
494 RealType compute(unsigned int index) const
|
Chris@16
|
495 {
|
Chris@16
|
496 return x[(k+index) % long_lag];
|
Chris@16
|
497 }
|
Chris@16
|
498
|
Chris@16
|
499 friend struct detail::subtract_with_carry_discard;
|
Chris@16
|
500
|
Chris@16
|
501 RealType do_update(std::size_t current, std::size_t short_index, RealType carry)
|
Chris@16
|
502 {
|
Chris@16
|
503 RealType delta = x[short_index] - x[current] - carry;
|
Chris@16
|
504 if(delta < 0) {
|
Chris@16
|
505 delta += RealType(1);
|
Chris@16
|
506 carry = RealType(1)/_modulus;
|
Chris@16
|
507 } else {
|
Chris@16
|
508 carry = 0;
|
Chris@16
|
509 }
|
Chris@16
|
510 x[current] = delta;
|
Chris@16
|
511 return carry;
|
Chris@16
|
512 }
|
Chris@16
|
513 /// \endcond
|
Chris@16
|
514 std::size_t k;
|
Chris@16
|
515 RealType carry;
|
Chris@16
|
516 RealType x[long_lag];
|
Chris@16
|
517 RealType _modulus;
|
Chris@16
|
518 };
|
Chris@16
|
519
|
Chris@16
|
520 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
|
Chris@16
|
521 // A definition is required even for integral static constants
|
Chris@16
|
522 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
|
Chris@16
|
523 const bool subtract_with_carry_01_engine<RealType, w, s, r>::has_fixed_range;
|
Chris@16
|
524 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
|
Chris@16
|
525 const std::size_t subtract_with_carry_01_engine<RealType, w, s, r>::word_size;
|
Chris@16
|
526 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
|
Chris@16
|
527 const std::size_t subtract_with_carry_01_engine<RealType, w, s, r>::long_lag;
|
Chris@16
|
528 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
|
Chris@16
|
529 const std::size_t subtract_with_carry_01_engine<RealType, w, s, r>::short_lag;
|
Chris@16
|
530 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
|
Chris@16
|
531 const uint32_t subtract_with_carry_01_engine<RealType, w, s, r>::default_seed;
|
Chris@16
|
532 #endif
|
Chris@16
|
533
|
Chris@16
|
534
|
Chris@16
|
535 /// \cond show_deprecated
|
Chris@16
|
536
|
Chris@16
|
537 template<class IntType, IntType m, unsigned s, unsigned r, IntType v>
|
Chris@16
|
538 class subtract_with_carry :
|
Chris@16
|
539 public subtract_with_carry_engine<IntType,
|
Chris@16
|
540 boost::static_log2<m>::value, s, r>
|
Chris@16
|
541 {
|
Chris@16
|
542 typedef subtract_with_carry_engine<IntType,
|
Chris@16
|
543 boost::static_log2<m>::value, s, r> base_type;
|
Chris@16
|
544 public:
|
Chris@16
|
545 subtract_with_carry() {}
|
Chris@16
|
546 BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(subtract_with_carry, Gen, gen)
|
Chris@16
|
547 { seed(gen); }
|
Chris@16
|
548 BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry,
|
Chris@16
|
549 IntType, val)
|
Chris@16
|
550 { seed(val); }
|
Chris@16
|
551 template<class It>
|
Chris@16
|
552 subtract_with_carry(It& first, It last) : base_type(first, last) {}
|
Chris@16
|
553 void seed() { base_type::seed(); }
|
Chris@16
|
554 BOOST_RANDOM_DETAIL_GENERATOR_SEED(subtract_with_carry, Gen, gen)
|
Chris@16
|
555 {
|
Chris@16
|
556 detail::generator_seed_seq<Gen> seq(gen);
|
Chris@16
|
557 base_type::seed(seq);
|
Chris@16
|
558 }
|
Chris@16
|
559 BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry, IntType, val)
|
Chris@16
|
560 { base_type::seed(val); }
|
Chris@16
|
561 template<class It>
|
Chris@16
|
562 void seed(It& first, It last) { base_type::seed(first, last); }
|
Chris@16
|
563 };
|
Chris@16
|
564
|
Chris@16
|
565 template<class RealType, int w, unsigned s, unsigned r, int v = 0>
|
Chris@16
|
566 class subtract_with_carry_01 :
|
Chris@16
|
567 public subtract_with_carry_01_engine<RealType, w, s, r>
|
Chris@16
|
568 {
|
Chris@16
|
569 typedef subtract_with_carry_01_engine<RealType, w, s, r> base_type;
|
Chris@16
|
570 public:
|
Chris@16
|
571 subtract_with_carry_01() {}
|
Chris@16
|
572 BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(subtract_with_carry_01, Gen, gen)
|
Chris@16
|
573 { seed(gen); }
|
Chris@16
|
574 BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry_01,
|
Chris@16
|
575 uint32_t, val)
|
Chris@16
|
576 { seed(val); }
|
Chris@16
|
577 template<class It>
|
Chris@16
|
578 subtract_with_carry_01(It& first, It last) : base_type(first, last) {}
|
Chris@16
|
579 void seed() { base_type::seed(); }
|
Chris@16
|
580 BOOST_RANDOM_DETAIL_GENERATOR_SEED(subtract_with_carry_01, Gen, gen)
|
Chris@16
|
581 {
|
Chris@16
|
582 detail::generator_seed_seq<Gen> seq(gen);
|
Chris@16
|
583 base_type::seed(seq);
|
Chris@16
|
584 }
|
Chris@16
|
585 BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry_01, uint32_t, val)
|
Chris@16
|
586 { base_type::seed(val); }
|
Chris@16
|
587 template<class It>
|
Chris@16
|
588 void seed(It& first, It last) { base_type::seed(first, last); }
|
Chris@16
|
589 };
|
Chris@16
|
590
|
Chris@16
|
591 /// \endcond
|
Chris@16
|
592
|
Chris@16
|
593 namespace detail {
|
Chris@16
|
594
|
Chris@16
|
595 template<class Engine>
|
Chris@16
|
596 struct generator_bits;
|
Chris@16
|
597
|
Chris@16
|
598 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
|
Chris@16
|
599 struct generator_bits<subtract_with_carry_01_engine<RealType, w, s, r> > {
|
Chris@16
|
600 static std::size_t value() { return w; }
|
Chris@16
|
601 };
|
Chris@16
|
602
|
Chris@16
|
603 template<class RealType, int w, unsigned s, unsigned r, int v>
|
Chris@16
|
604 struct generator_bits<subtract_with_carry_01<RealType, w, s, r, v> > {
|
Chris@16
|
605 static std::size_t value() { return w; }
|
Chris@16
|
606 };
|
Chris@16
|
607
|
Chris@16
|
608 }
|
Chris@16
|
609
|
Chris@16
|
610 } // namespace random
|
Chris@16
|
611 } // namespace boost
|
Chris@16
|
612
|
Chris@16
|
613 #endif // BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP
|