xor_combine.hpp 6.9 KB

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