xor_combine.hpp 7.0 KB

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