xor_combine.hpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  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 result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return (std::min)((URNG1::min)(), (URNG2::min)()); }
  119. /** Returns the largest value that the generator can produce. */
  120. static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () { return (std::max)((URNG1::min)(), (URNG2::max)()); }
  121. /**
  122. * Writes the textual representation of the generator to a @c std::ostream.
  123. */
  124. BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, xor_combine_engine, s)
  125. {
  126. os << s._rng1 << ' ' << s._rng2;
  127. return os;
  128. }
  129. /**
  130. * Reads the textual representation of the generator from a @c std::istream.
  131. */
  132. BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, xor_combine_engine, s)
  133. {
  134. is >> s._rng1 >> std::ws >> s._rng2;
  135. return is;
  136. }
  137. /** Returns true if the two generators will produce identical sequences. */
  138. BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(xor_combine_engine, x, y)
  139. { return x._rng1 == y._rng1 && x._rng2 == y._rng2; }
  140. /** Returns true if the two generators will produce different sequences. */
  141. BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(xor_combine_engine)
  142. private:
  143. base1_type _rng1;
  144. base2_type _rng2;
  145. };
  146. #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
  147. // A definition is required even for integral static constants
  148. template<class URNG1, int s1, class URNG2, int s2>
  149. const bool xor_combine_engine<URNG1, s1, URNG2, s2>::has_fixed_range;
  150. template<class URNG1, int s1, class URNG2, int s2>
  151. const int xor_combine_engine<URNG1, s1, URNG2, s2>::shift1;
  152. template<class URNG1, int s1, class URNG2, int s2>
  153. const int xor_combine_engine<URNG1, s1, URNG2, s2>::shift2;
  154. #endif
  155. /// \cond show_private
  156. /** Provided for backwards compatibility. */
  157. template<class URNG1, int s1, class URNG2, int s2,
  158. typename URNG1::result_type v = 0>
  159. class xor_combine : public xor_combine_engine<URNG1, s1, URNG2, s2>
  160. {
  161. typedef xor_combine_engine<URNG1, s1, URNG2, s2> base_type;
  162. public:
  163. typedef typename base_type::result_type result_type;
  164. xor_combine() {}
  165. xor_combine(result_type val) : base_type(val) {}
  166. template<class It>
  167. xor_combine(It& first, It last) : base_type(first, last) {}
  168. xor_combine(const URNG1 & rng1, const URNG2 & rng2)
  169. : base_type(rng1, rng2) { }
  170. result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (std::min)((this->base1().min)(), (this->base2().min)()); }
  171. result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (std::max)((this->base1().min)(), (this->base2().max)()); }
  172. };
  173. /// \endcond
  174. } // namespace random
  175. } // namespace boost
  176. #endif // BOOST_RANDOM_XOR_COMBINE_HPP