additive_combine.hpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /* boost random/additive_combine.hpp header file
  2. *
  3. * Copyright Jens Maurer 2000-2001
  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. * Revision history
  13. * 2001-02-18 moved to individual header files
  14. */
  15. #ifndef BOOST_RANDOM_ADDITIVE_COMBINE_HPP
  16. #define BOOST_RANDOM_ADDITIVE_COMBINE_HPP
  17. #include <istream>
  18. #include <iosfwd>
  19. #include <algorithm> // for std::min and std::max
  20. #include <boost/config.hpp>
  21. #include <boost/cstdint.hpp>
  22. #include <boost/random/detail/config.hpp>
  23. #include <boost/random/detail/operators.hpp>
  24. #include <boost/random/detail/seed.hpp>
  25. #include <boost/random/linear_congruential.hpp>
  26. namespace boost {
  27. namespace random {
  28. /**
  29. * An instantiation of class template @c additive_combine_engine models a
  30. * \pseudo_random_number_generator. It combines two multiplicative
  31. * \linear_congruential_engine number generators, i.e. those with @c c = 0.
  32. * It is described in
  33. *
  34. * @blockquote
  35. * "Efficient and Portable Combined Random Number Generators", Pierre L'Ecuyer,
  36. * Communications of the ACM, Vol. 31, No. 6, June 1988, pp. 742-749, 774
  37. * @endblockquote
  38. *
  39. * The template parameters MLCG1 and MLCG2 shall denote two different
  40. * \linear_congruential_engine number generators, each with c = 0. Each
  41. * invocation returns a random number
  42. * X(n) := (MLCG1(n) - MLCG2(n)) mod (m1 - 1),
  43. * where m1 denotes the modulus of MLCG1.
  44. */
  45. template<class MLCG1, class MLCG2>
  46. class additive_combine_engine
  47. {
  48. public:
  49. typedef MLCG1 first_base;
  50. typedef MLCG2 second_base;
  51. typedef typename MLCG1::result_type result_type;
  52. // Required by old Boost.Random concept
  53. BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
  54. /**
  55. * Returns the smallest value that the generator can produce
  56. */
  57. static BOOST_CONSTEXPR result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
  58. { return 1; }
  59. /**
  60. * Returns the largest value that the generator can produce
  61. */
  62. static BOOST_CONSTEXPR result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
  63. { return MLCG1::modulus-1; }
  64. /**
  65. * Constructs an @c additive_combine_engine using the
  66. * default constructors of the two base generators.
  67. */
  68. additive_combine_engine() : _mlcg1(), _mlcg2() { }
  69. /**
  70. * Constructs an @c additive_combine_engine, using seed as
  71. * the constructor argument for both base generators.
  72. */
  73. BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(additive_combine_engine,
  74. result_type, seed_arg)
  75. {
  76. _mlcg1.seed(seed_arg);
  77. _mlcg2.seed(seed_arg);
  78. }
  79. /**
  80. * Constructs an @c additive_combine_engine, using seq as
  81. * the constructor argument for both base generators.
  82. *
  83. * @xmlwarning
  84. * The semantics of this function are liable to change.
  85. * A @c seed_seq is designed to generate all the seeds
  86. * in one shot, but this seeds the two base engines
  87. * independantly and probably ends up giving the same
  88. * sequence to both.
  89. * @endxmlwarning
  90. */
  91. BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(additive_combine_engine,
  92. SeedSeq, seq)
  93. {
  94. _mlcg1.seed(seq);
  95. _mlcg2.seed(seq);
  96. }
  97. /**
  98. * Constructs an @c additive_combine_engine, using
  99. * @c seed1 and @c seed2 as the constructor argument to
  100. * the first and second base generators, respectively.
  101. */
  102. additive_combine_engine(typename MLCG1::result_type seed1,
  103. typename MLCG2::result_type seed2)
  104. : _mlcg1(seed1), _mlcg2(seed2) { }
  105. /**
  106. * Contructs an @c additive_combine_engine with
  107. * values from the range defined by the input iterators first
  108. * and last. first will be modified to point to the element
  109. * after the last one used.
  110. *
  111. * Throws: @c std::invalid_argument if the input range is too small.
  112. *
  113. * Exception Safety: Basic
  114. */
  115. template<class It> additive_combine_engine(It& first, It last)
  116. : _mlcg1(first, last), _mlcg2(first, last) { }
  117. /**
  118. * Seeds an @c additive_combine_engine using the default
  119. * seeds of the two base generators.
  120. */
  121. void seed()
  122. {
  123. _mlcg1.seed();
  124. _mlcg2.seed();
  125. }
  126. /**
  127. * Seeds an @c additive_combine_engine, using @c seed as the
  128. * seed for both base generators.
  129. */
  130. BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(additive_combine_engine,
  131. result_type, seed_arg)
  132. {
  133. _mlcg1.seed(seed_arg);
  134. _mlcg2.seed(seed_arg);
  135. }
  136. /**
  137. * Seeds an @c additive_combine_engine, using @c seq to
  138. * seed both base generators.
  139. *
  140. * See the warning on the corresponding constructor.
  141. */
  142. BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(additive_combine_engine,
  143. SeedSeq, seq)
  144. {
  145. _mlcg1.seed(seq);
  146. _mlcg2.seed(seq);
  147. }
  148. /**
  149. * Seeds an @c additive_combine generator, using @c seed1 and @c seed2 as
  150. * the seeds to the first and second base generators, respectively.
  151. */
  152. void seed(typename MLCG1::result_type seed1,
  153. typename MLCG2::result_type seed2)
  154. {
  155. _mlcg1.seed(seed1);
  156. _mlcg2.seed(seed2);
  157. }
  158. /**
  159. * Seeds an @c additive_combine_engine with
  160. * values from the range defined by the input iterators first
  161. * and last. first will be modified to point to the element
  162. * after the last one used.
  163. *
  164. * Throws: @c std::invalid_argument if the input range is too small.
  165. *
  166. * Exception Safety: Basic
  167. */
  168. template<class It> void seed(It& first, It last)
  169. {
  170. _mlcg1.seed(first, last);
  171. _mlcg2.seed(first, last);
  172. }
  173. /** Returns the next value of the generator. */
  174. result_type operator()() {
  175. result_type val1 = _mlcg1();
  176. result_type val2 = _mlcg2();
  177. if(val2 < val1) return val1 - val2;
  178. else return val1 - val2 + MLCG1::modulus - 1;
  179. }
  180. /** Fills a range with random values */
  181. template<class Iter>
  182. void generate(Iter first, Iter last)
  183. { detail::generate_from_int(*this, first, last); }
  184. /** Advances the state of the generator by @c z. */
  185. void discard(boost::uintmax_t z)
  186. {
  187. _mlcg1.discard(z);
  188. _mlcg2.discard(z);
  189. }
  190. /**
  191. * Writes the state of an @c additive_combine_engine to a @c
  192. * std::ostream. The textual representation of an @c
  193. * additive_combine_engine is the textual representation of
  194. * the first base generator followed by the textual representation
  195. * of the second base generator.
  196. */
  197. BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, additive_combine_engine, r)
  198. { os << r._mlcg1 << ' ' << r._mlcg2; return os; }
  199. /**
  200. * Reads the state of an @c additive_combine_engine from a
  201. * @c std::istream.
  202. */
  203. BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, additive_combine_engine, r)
  204. { is >> r._mlcg1 >> std::ws >> r._mlcg2; return is; }
  205. /**
  206. * Returns: true iff the two @c additive_combine_engines will
  207. * produce the same sequence of values.
  208. */
  209. BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(additive_combine_engine, x, y)
  210. { return x._mlcg1 == y._mlcg1 && x._mlcg2 == y._mlcg2; }
  211. /**
  212. * Returns: true iff the two @c additive_combine_engines will
  213. * produce different sequences of values.
  214. */
  215. BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(additive_combine_engine)
  216. private:
  217. MLCG1 _mlcg1;
  218. MLCG2 _mlcg2;
  219. };
  220. #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
  221. template<class MLCG1, class MLCG2>
  222. const bool additive_combine_engine<MLCG1, MLCG2>::has_fixed_range;
  223. #endif
  224. /// \cond show_deprecated
  225. /** Provided for backwards compatibility. */
  226. template<class MLCG1, class MLCG2, typename MLCG1::result_type val = 0>
  227. class additive_combine : public additive_combine_engine<MLCG1, MLCG2>
  228. {
  229. typedef additive_combine_engine<MLCG1, MLCG2> base_t;
  230. public:
  231. typedef typename base_t::result_type result_type;
  232. additive_combine() {}
  233. template<class T>
  234. additive_combine(T& arg) : base_t(arg) {}
  235. template<class T>
  236. additive_combine(const T& arg) : base_t(arg) {}
  237. template<class It>
  238. additive_combine(It& first, It last) : base_t(first, last) {}
  239. };
  240. /// \endcond
  241. /**
  242. * The specialization \ecuyer1988 was suggested in
  243. *
  244. * @blockquote
  245. * "Efficient and Portable Combined Random Number Generators", Pierre L'Ecuyer,
  246. * Communications of the ACM, Vol. 31, No. 6, June 1988, pp. 742-749, 774
  247. * @endblockquote
  248. */
  249. typedef additive_combine_engine<
  250. linear_congruential_engine<uint32_t, 40014, 0, 2147483563>,
  251. linear_congruential_engine<uint32_t, 40692, 0, 2147483399>
  252. > ecuyer1988;
  253. } // namespace random
  254. using random::ecuyer1988;
  255. } // namespace boost
  256. #endif // BOOST_RANDOM_ADDITIVE_COMBINE_HPP