1 | /* boost random/xor_combine.hpp header file |
2 | * |
3 | * Copyright Jens Maurer 2002 |
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 | */ |
13 | |
14 | #ifndef BOOST_RANDOM_XOR_COMBINE_HPP |
15 | #define BOOST_RANDOM_XOR_COMBINE_HPP |
16 | |
17 | #include <istream> |
18 | #include <iosfwd> |
19 | #include <cassert> |
20 | #include <algorithm> // for std::min and std::max |
21 | #include <boost/config.hpp> |
22 | #include <boost/limits.hpp> |
23 | #include <boost/cstdint.hpp> // uint32_t |
24 | #include <boost/random/detail/config.hpp> |
25 | #include <boost/random/detail/seed.hpp> |
26 | #include <boost/random/detail/seed_impl.hpp> |
27 | #include <boost/random/detail/operators.hpp> |
28 | |
29 | namespace boost { |
30 | namespace random { |
31 | |
32 | /** |
33 | * Instantiations of @c xor_combine_engine model a |
34 | * \pseudo_random_number_generator. To produce its output it |
35 | * invokes each of the base generators, shifts their results |
36 | * and xors them together. |
37 | */ |
38 | template<class URNG1, int s1, class URNG2, int s2> |
39 | class xor_combine_engine |
40 | { |
41 | public: |
42 | typedef URNG1 base1_type; |
43 | typedef URNG2 base2_type; |
44 | typedef typename base1_type::result_type result_type; |
45 | |
46 | BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); |
47 | BOOST_STATIC_CONSTANT(int, shift1 = s1); |
48 | BOOST_STATIC_CONSTANT(int, shift2 = s2); |
49 | |
50 | /** |
51 | * Constructors a @c xor_combine_engine by default constructing |
52 | * both base generators. |
53 | */ |
54 | xor_combine_engine() : _rng1(), _rng2() { } |
55 | |
56 | /** Constructs a @c xor_combine by copying two base generators. */ |
57 | xor_combine_engine(const base1_type & rng1, const base2_type & rng2) |
58 | : _rng1(rng1), _rng2(rng2) { } |
59 | |
60 | /** |
61 | * Constructs a @c xor_combine_engine, seeding both base generators |
62 | * with @c v. |
63 | * |
64 | * @xmlwarning |
65 | * The exact algorithm used by this function may change in the future. |
66 | * @endxmlwarning |
67 | */ |
68 | BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(xor_combine_engine, |
69 | result_type, v) |
70 | { seed(v); } |
71 | |
72 | /** |
73 | * Constructs a @c xor_combine_engine, seeding both base generators |
74 | * with values produced by @c seq. |
75 | */ |
76 | BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(xor_combine_engine, |
77 | SeedSeq, seq) |
78 | { seed(seq); } |
79 | |
80 | /** |
81 | * Constructs a @c xor_combine_engine, seeding both base generators |
82 | * with values from the iterator range [first, last) and changes |
83 | * first to point to the element after the last one used. If there |
84 | * are not enough elements in the range to seed both generators, |
85 | * throws @c std::invalid_argument. |
86 | */ |
87 | template<class It> xor_combine_engine(It& first, It last) |
88 | : _rng1(first, last), _rng2( /* advanced by other call */ first, last) { } |
89 | |
90 | /** Calls @c seed() for both base generators. */ |
91 | void seed() { _rng1.seed(); _rng2.seed(); } |
92 | |
93 | /** @c seeds both base generators with @c v. */ |
94 | BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(xor_combine_engine, result_type, v) |
95 | { _rng1.seed(v); _rng2.seed(v); } |
96 | |
97 | /** @c seeds both base generators with values produced by @c seq. */ |
98 | BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(xor_combine_engine, SeedSeq, seq) |
99 | { _rng1.seed(seq); _rng2.seed(seq); } |
100 | |
101 | /** |
102 | * seeds both base generators with values from the iterator |
103 | * range [first, last) and changes first to point to the element |
104 | * after the last one used. If there are not enough elements in |
105 | * the range to seed both generators, throws @c std::invalid_argument. |
106 | */ |
107 | template<class It> void seed(It& first, It last) |
108 | { |
109 | _rng1.seed(first, last); |
110 | _rng2.seed(first, last); |
111 | } |
112 | |
113 | /** Returns the first base generator. */ |
114 | const base1_type& base1() const { return _rng1; } |
115 | |
116 | /** Returns the second base generator. */ |
117 | const base2_type& base2() const { return _rng2; } |
118 | |
119 | /** Returns the next value of the generator. */ |
120 | result_type operator()() |
121 | { |
122 | return (_rng1() << s1) ^ (_rng2() << s2); |
123 | } |
124 | |
125 | /** Fills a range with random values */ |
126 | template<class Iter> |
127 | void generate(Iter first, Iter last) |
128 | { detail::generate_from_int(*this, first, last); } |
129 | |
130 | /** Advances the state of the generator by @c z. */ |
131 | void discard(boost::uintmax_t z) |
132 | { |
133 | _rng1.discard(z); |
134 | _rng2.discard(z); |
135 | } |
136 | |
137 | /** Returns the smallest value that the generator can produce. */ |
138 | static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return (std::min)((URNG1::min)(), (URNG2::min)()); } |
139 | /** Returns the largest value that the generator can produce. */ |
140 | static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () { return (std::max)((URNG1::min)(), (URNG2::max)()); } |
141 | |
142 | /** |
143 | * Writes the textual representation of the generator to a @c std::ostream. |
144 | */ |
145 | BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, xor_combine_engine, s) |
146 | { |
147 | os << s._rng1 << ' ' << s._rng2; |
148 | return os; |
149 | } |
150 | |
151 | /** |
152 | * Reads the textual representation of the generator from a @c std::istream. |
153 | */ |
154 | BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, xor_combine_engine, s) |
155 | { |
156 | is >> s._rng1 >> std::ws >> s._rng2; |
157 | return is; |
158 | } |
159 | |
160 | /** Returns true if the two generators will produce identical sequences. */ |
161 | BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(xor_combine_engine, x, y) |
162 | { return x._rng1 == y._rng1 && x._rng2 == y._rng2; } |
163 | |
164 | /** Returns true if the two generators will produce different sequences. */ |
165 | BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(xor_combine_engine) |
166 | |
167 | private: |
168 | base1_type _rng1; |
169 | base2_type _rng2; |
170 | }; |
171 | |
172 | #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION |
173 | // A definition is required even for integral static constants |
174 | template<class URNG1, int s1, class URNG2, int s2> |
175 | const bool xor_combine_engine<URNG1, s1, URNG2, s2>::has_fixed_range; |
176 | template<class URNG1, int s1, class URNG2, int s2> |
177 | const int xor_combine_engine<URNG1, s1, URNG2, s2>::shift1; |
178 | template<class URNG1, int s1, class URNG2, int s2> |
179 | const int xor_combine_engine<URNG1, s1, URNG2, s2>::shift2; |
180 | #endif |
181 | |
182 | /// \cond show_private |
183 | |
184 | /** Provided for backwards compatibility. */ |
185 | template<class URNG1, int s1, class URNG2, int s2, |
186 | typename URNG1::result_type v = 0> |
187 | class xor_combine : public xor_combine_engine<URNG1, s1, URNG2, s2> |
188 | { |
189 | typedef xor_combine_engine<URNG1, s1, URNG2, s2> base_type; |
190 | public: |
191 | typedef typename base_type::result_type result_type; |
192 | xor_combine() {} |
193 | xor_combine(result_type val) : base_type(val) {} |
194 | template<class It> |
195 | xor_combine(It& first, It last) : base_type(first, last) {} |
196 | xor_combine(const URNG1 & rng1, const URNG2 & rng2) |
197 | : base_type(rng1, rng2) { } |
198 | |
199 | result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (std::min)((this->base1().min)(), (this->base2().min)()); } |
200 | result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (std::max)((this->base1().min)(), (this->base2().max)()); } |
201 | }; |
202 | |
203 | /// \endcond |
204 | |
205 | } // namespace random |
206 | } // namespace boost |
207 | |
208 | #endif // BOOST_RANDOM_XOR_COMBINE_HPP |
209 | |