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 */ xor_combine_engine()54 xor_combine_engine() : _rng1(), _rng2() { } 55 56 /** Constructs a @c xor_combine by copying two base generators. */ xor_combine_engine(const base1_type & rng1,const base2_type & rng2)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 */ BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(xor_combine_engine,result_type,v)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 */ BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(xor_combine_engine,SeedSeq,seq)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 */ xor_combine_engine(It & first,It last)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. */ seed()91 void seed() { _rng1.seed(); _rng2.seed(); } 92 93 /** @c seeds both base generators with @c v. */ BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(xor_combine_engine,result_type,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. */ BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(xor_combine_engine,SeedSeq,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 */ seed(It & first,It last)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. */ base1() const114 const base1_type& base1() const { return _rng1; } 115 116 /** Returns the second base generator. */ base2() const117 const base2_type& base2() const { return _rng2; } 118 119 /** Returns the next value of the generator. */ operator ()()120 result_type operator()() 121 { 122 return (_rng1() << s1) ^ (_rng2() << s2); 123 } 124 125 /** Fills a range with random values */ 126 template<class Iter> generate(Iter first,Iter last)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. */ discard(boost::uintmax_t 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. */ BOOST_PREVENT_MACRO_SUBSTITUTION()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. */ BOOST_PREVENT_MACRO_SUBSTITUTION()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 */ BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os,xor_combine_engine,s)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 */ BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is,xor_combine_engine,s)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. */ BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(xor_combine_engine,x,y)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; xor_combine()192 xor_combine() {} xor_combine(result_type val)193 xor_combine(result_type val) : base_type(val) {} 194 template<class It> xor_combine(It & first,It last)195 xor_combine(It& first, It last) : base_type(first, last) {} xor_combine(const URNG1 & rng1,const URNG2 & rng2)196 xor_combine(const URNG1 & rng1, const URNG2 & rng2) 197 : base_type(rng1, rng2) { } 198 BOOST_PREVENT_MACRO_SUBSTITUTION() const199 result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (std::min)((this->base1().min)(), (this->base2().min)()); } BOOST_PREVENT_MACRO_SUBSTITUTION() const200 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