/Src/Dependencies/Boost/boost/random/lagged_fibonacci.hpp

http://hadesmem.googlecode.com/ · C++ Header · 536 lines · 300 code · 65 blank · 171 comment · 18 complexity · da820397f5ea16cb0472dfeca31a73fd MD5 · raw file

  1. /* boost random/lagged_fibonacci.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: lagged_fibonacci.hpp 72951 2011-07-07 04:57:37Z steven_watanabe $
  11. *
  12. * Revision history
  13. * 2001-02-18 moved to individual header files
  14. */
  15. #ifndef BOOST_RANDOM_LAGGED_FIBONACCI_HPP
  16. #define BOOST_RANDOM_LAGGED_FIBONACCI_HPP
  17. #include <istream>
  18. #include <iosfwd>
  19. #include <algorithm> // std::max
  20. #include <iterator>
  21. #include <boost/config/no_tr1/cmath.hpp> // std::pow
  22. #include <boost/config.hpp>
  23. #include <boost/limits.hpp>
  24. #include <boost/cstdint.hpp>
  25. #include <boost/integer/integer_mask.hpp>
  26. #include <boost/random/linear_congruential.hpp>
  27. #include <boost/random/uniform_01.hpp>
  28. #include <boost/random/detail/config.hpp>
  29. #include <boost/random/detail/seed.hpp>
  30. #include <boost/random/detail/operators.hpp>
  31. #include <boost/random/detail/generator_seed_seq.hpp>
  32. namespace boost {
  33. namespace random {
  34. /**
  35. * Instantiations of class template \lagged_fibonacci_engine model a
  36. * \pseudo_random_number_generator. It uses a lagged Fibonacci
  37. * algorithm with two lags @c p and @c q:
  38. * x(i) = x(i-p) + x(i-q) (mod 2<sup>w</sup>) with p > q.
  39. */
  40. template<class UIntType, int w, unsigned int p, unsigned int q>
  41. class lagged_fibonacci_engine
  42. {
  43. public:
  44. typedef UIntType result_type;
  45. BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
  46. BOOST_STATIC_CONSTANT(int, word_size = w);
  47. BOOST_STATIC_CONSTANT(unsigned int, long_lag = p);
  48. BOOST_STATIC_CONSTANT(unsigned int, short_lag = q);
  49. BOOST_STATIC_CONSTANT(UIntType, default_seed = 331u);
  50. /** Returns the smallest value that the generator can produce. */
  51. static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return 0; }
  52. /** Returns the largest value that the generator can produce. */
  53. static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
  54. { return low_bits_mask_t<w>::sig_bits; }
  55. /** Creates a new @c lagged_fibonacci_engine and calls @c seed(). */
  56. lagged_fibonacci_engine() { seed(); }
  57. /** Creates a new @c lagged_fibonacci_engine and calls @c seed(value). */
  58. BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci_engine,
  59. UIntType, value)
  60. { seed(value); }
  61. /** Creates a new @c lagged_fibonacci_engine and calls @c seed(seq). */
  62. BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(lagged_fibonacci_engine,
  63. SeedSeq, seq)
  64. { seed(seq); }
  65. /**
  66. * Creates a new @c lagged_fibonacci_engine and calls @c seed(first, last).
  67. */
  68. template<class It> lagged_fibonacci_engine(It& first, It last)
  69. { seed(first, last); }
  70. // compiler-generated copy ctor and assignment operator are fine
  71. /** Calls @c seed(default_seed). */
  72. void seed() { seed(default_seed); }
  73. /**
  74. * Sets the state of the generator to values produced by
  75. * a \minstd_rand0 generator.
  76. */
  77. BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(lagged_fibonacci_engine,
  78. UIntType, value)
  79. {
  80. minstd_rand0 intgen(static_cast<boost::uint32_t>(value));
  81. detail::generator_seed_seq<minstd_rand0> gen(intgen);
  82. seed(gen);
  83. }
  84. /**
  85. * Sets the state of the generator using values produced by seq.
  86. */
  87. BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(lagged_fibonacci_engine, SeedSeq, seq)
  88. {
  89. detail::seed_array_int<w>(seq, x);
  90. i = long_lag;
  91. }
  92. /**
  93. * Sets the state of the generator to values from the iterator
  94. * range [first, last). If there are not enough elements in the
  95. * range [first, last) throws @c std::invalid_argument.
  96. */
  97. template<class It>
  98. void seed(It& first, It last)
  99. {
  100. detail::fill_array_int<w>(first, last, x);
  101. i = long_lag;
  102. }
  103. /** Returns the next value of the generator. */
  104. result_type operator()()
  105. {
  106. if(i >= long_lag)
  107. fill();
  108. return x[i++];
  109. }
  110. /** Fills a range with random values */
  111. template<class Iter>
  112. void generate(Iter first, Iter last)
  113. { detail::generate_from_int(*this, first, last); }
  114. /** Advances the state of the generator by @c z. */
  115. void discard(boost::uintmax_t z)
  116. {
  117. for(boost::uintmax_t j = 0; j < z; ++j) {
  118. (*this)();
  119. }
  120. }
  121. /**
  122. * Writes the textual representation of the generator to a @c std::ostream.
  123. */
  124. BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, lagged_fibonacci_engine, f)
  125. {
  126. os << f.i;
  127. for(unsigned int i = 0; i < f.long_lag; ++i)
  128. os << ' ' << f.x[i];
  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, lagged_fibonacci_engine, f)
  135. {
  136. is >> f.i >> std::ws;
  137. for(unsigned int i = 0; i < f.long_lag; ++i)
  138. is >> f.x[i] >> std::ws;
  139. return is;
  140. }
  141. /**
  142. * Returns true if the two generators will produce identical
  143. * sequences of outputs.
  144. */
  145. BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(lagged_fibonacci_engine, x, y)
  146. { return x.i == y.i && std::equal(x.x, x.x+long_lag, y.x); }
  147. /**
  148. * Returns true if the two generators will produce different
  149. * sequences of outputs.
  150. */
  151. BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(lagged_fibonacci_engine)
  152. private:
  153. /// \cond show_private
  154. void fill();
  155. /// \endcond
  156. unsigned int i;
  157. UIntType x[long_lag];
  158. };
  159. #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
  160. // A definition is required even for integral static constants
  161. template<class UIntType, int w, unsigned int p, unsigned int q>
  162. const bool lagged_fibonacci_engine<UIntType, w, p, q>::has_fixed_range;
  163. template<class UIntType, int w, unsigned int p, unsigned int q>
  164. const unsigned int lagged_fibonacci_engine<UIntType, w, p, q>::long_lag;
  165. template<class UIntType, int w, unsigned int p, unsigned int q>
  166. const unsigned int lagged_fibonacci_engine<UIntType, w, p, q>::short_lag;
  167. template<class UIntType, int w, unsigned int p, unsigned int q>
  168. const UIntType lagged_fibonacci_engine<UIntType, w, p, q>::default_seed;
  169. #endif
  170. /// \cond show_private
  171. template<class UIntType, int w, unsigned int p, unsigned int q>
  172. void lagged_fibonacci_engine<UIntType, w, p, q>::fill()
  173. {
  174. // two loops to avoid costly modulo operations
  175. { // extra scope for MSVC brokenness w.r.t. for scope
  176. for(unsigned int j = 0; j < short_lag; ++j)
  177. x[j] = (x[j] + x[j+(long_lag-short_lag)]) & low_bits_mask_t<w>::sig_bits;
  178. }
  179. for(unsigned int j = short_lag; j < long_lag; ++j)
  180. x[j] = (x[j] + x[j-short_lag]) & low_bits_mask_t<w>::sig_bits;
  181. i = 0;
  182. }
  183. /// \endcond
  184. /// \cond show_deprecated
  185. // provided for backwards compatibility
  186. template<class UIntType, int w, unsigned int p, unsigned int q, UIntType v = 0>
  187. class lagged_fibonacci : public lagged_fibonacci_engine<UIntType, w, p, q>
  188. {
  189. typedef lagged_fibonacci_engine<UIntType, w, p, q> base_type;
  190. public:
  191. lagged_fibonacci() {}
  192. BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci, UIntType, val)
  193. { this->seed(val); }
  194. BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(lagged_fibonacci, SeedSeq, seq)
  195. { this->seed(seq); }
  196. template<class It>
  197. lagged_fibonacci(It& first, It last) : base_type(first, last) {}
  198. };
  199. /// \endcond
  200. // lagged Fibonacci generator for the range [0..1)
  201. // contributed by Matthias Troyer
  202. // for p=55, q=24 originally by G. J. Mitchell and D. P. Moore 1958
  203. /**
  204. * Instantiations of class template @c lagged_fibonacci_01 model a
  205. * \pseudo_random_number_generator. It uses a lagged Fibonacci
  206. * algorithm with two lags @c p and @c q, evaluated in floating-point
  207. * arithmetic: x(i) = x(i-p) + x(i-q) (mod 1) with p > q. See
  208. *
  209. * @blockquote
  210. * "Uniform random number generators for supercomputers", Richard Brent,
  211. * Proc. of Fifth Australian Supercomputer Conference, Melbourne,
  212. * Dec. 1992, pp. 704-706.
  213. * @endblockquote
  214. *
  215. * @xmlnote
  216. * The quality of the generator crucially depends on the choice
  217. * of the parameters. User code should employ one of the sensibly
  218. * parameterized generators such as \lagged_fibonacci607 instead.
  219. * @endxmlnote
  220. *
  221. * The generator requires considerable amounts of memory for the storage
  222. * of its state array. For example, \lagged_fibonacci607 requires about
  223. * 4856 bytes and \lagged_fibonacci44497 requires about 350 KBytes.
  224. */
  225. template<class RealType, int w, unsigned int p, unsigned int q>
  226. class lagged_fibonacci_01_engine
  227. {
  228. public:
  229. typedef RealType result_type;
  230. BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
  231. BOOST_STATIC_CONSTANT(int, word_size = w);
  232. BOOST_STATIC_CONSTANT(unsigned int, long_lag = p);
  233. BOOST_STATIC_CONSTANT(unsigned int, short_lag = q);
  234. BOOST_STATIC_CONSTANT(boost::uint32_t, default_seed = 331u);
  235. /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(). */
  236. lagged_fibonacci_01_engine() { seed(); }
  237. /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(value). */
  238. BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci_01_engine, uint32_t, value)
  239. { seed(value); }
  240. /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(gen). */
  241. BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(lagged_fibonacci_01_engine, SeedSeq, seq)
  242. { seed(seq); }
  243. template<class It> lagged_fibonacci_01_engine(It& first, It last)
  244. { seed(first, last); }
  245. // compiler-generated copy ctor and assignment operator are fine
  246. /** Calls seed(default_seed). */
  247. void seed() { seed(default_seed); }
  248. /**
  249. * Constructs a \minstd_rand0 generator with the constructor parameter
  250. * value and calls seed with it. Distinct seeds in the range
  251. * [1, 2147483647) will produce generators with different states. Other
  252. * seeds will be equivalent to some seed within this range. See
  253. * \linear_congruential_engine for details.
  254. */
  255. BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(lagged_fibonacci_01_engine, boost::uint32_t, value)
  256. {
  257. minstd_rand0 intgen(value);
  258. detail::generator_seed_seq<minstd_rand0> gen(intgen);
  259. seed(gen);
  260. }
  261. /**
  262. * Seeds this @c lagged_fibonacci_01_engine using values produced by
  263. * @c seq.generate.
  264. */
  265. BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(lagged_fibonacci_01_engine, SeedSeq, seq)
  266. {
  267. detail::seed_array_real<w>(seq, x);
  268. i = long_lag;
  269. }
  270. /**
  271. * Seeds this @c lagged_fibonacci_01_engine using values from the
  272. * iterator range [first, last). If there are not enough elements
  273. * in the range, throws @c std::invalid_argument.
  274. */
  275. template<class It>
  276. void seed(It& first, It last)
  277. {
  278. detail::fill_array_real<w>(first, last, x);
  279. i = long_lag;
  280. }
  281. /** Returns the smallest value that the generator can produce. */
  282. static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return result_type(0); }
  283. /** Returns the upper bound of the generators outputs. */
  284. static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () { return result_type(1); }
  285. /** Returns the next value of the generator. */
  286. result_type operator()()
  287. {
  288. if(i >= long_lag)
  289. fill();
  290. return x[i++];
  291. }
  292. /** Fills a range with random values */
  293. template<class Iter>
  294. void generate(Iter first, Iter last)
  295. { return detail::generate_from_real(*this, first, last); }
  296. /** Advances the state of the generator by @c z. */
  297. void discard(boost::uintmax_t z)
  298. {
  299. for(boost::uintmax_t j = 0; j < z; ++j) {
  300. (*this)();
  301. }
  302. }
  303. /**
  304. * Writes the textual representation of the generator to a @c std::ostream.
  305. */
  306. BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, lagged_fibonacci_01_engine, f)
  307. {
  308. // allow for Koenig lookup
  309. using std::pow;
  310. os << f.i;
  311. std::ios_base::fmtflags oldflags = os.flags(os.dec | os.fixed | os.left);
  312. for(unsigned int i = 0; i < f.long_lag; ++i)
  313. os << ' ' << f.x[i] * f.modulus();
  314. os.flags(oldflags);
  315. return os;
  316. }
  317. /**
  318. * Reads the textual representation of the generator from a @c std::istream.
  319. */
  320. BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, lagged_fibonacci_01_engine, f)
  321. {
  322. is >> f.i;
  323. for(unsigned int i = 0; i < f.long_lag; ++i) {
  324. typename lagged_fibonacci_01_engine::result_type value;
  325. is >> std::ws >> value;
  326. f.x[i] = value / f.modulus();
  327. }
  328. return is;
  329. }
  330. /**
  331. * Returns true if the two generators will produce identical
  332. * sequences of outputs.
  333. */
  334. BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(lagged_fibonacci_01_engine, x, y)
  335. { return x.i == y.i && std::equal(x.x, x.x+long_lag, y.x); }
  336. /**
  337. * Returns true if the two generators will produce different
  338. * sequences of outputs.
  339. */
  340. BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(lagged_fibonacci_01_engine)
  341. private:
  342. /// \cond show_private
  343. void fill();
  344. static RealType modulus()
  345. {
  346. using std::pow;
  347. return pow(RealType(2), word_size);
  348. }
  349. /// \endcond
  350. unsigned int i;
  351. RealType x[long_lag];
  352. };
  353. #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
  354. // A definition is required even for integral static constants
  355. template<class RealType, int w, unsigned int p, unsigned int q>
  356. const bool lagged_fibonacci_01_engine<RealType, w, p, q>::has_fixed_range;
  357. template<class RealType, int w, unsigned int p, unsigned int q>
  358. const unsigned int lagged_fibonacci_01_engine<RealType, w, p, q>::long_lag;
  359. template<class RealType, int w, unsigned int p, unsigned int q>
  360. const unsigned int lagged_fibonacci_01_engine<RealType, w, p, q>::short_lag;
  361. template<class RealType, int w, unsigned int p, unsigned int q>
  362. const int lagged_fibonacci_01_engine<RealType,w,p,q>::word_size;
  363. template<class RealType, int w, unsigned int p, unsigned int q>
  364. const boost::uint32_t lagged_fibonacci_01_engine<RealType,w,p,q>::default_seed;
  365. #endif
  366. /// \cond show_private
  367. template<class RealType, int w, unsigned int p, unsigned int q>
  368. void lagged_fibonacci_01_engine<RealType, w, p, q>::fill()
  369. {
  370. // two loops to avoid costly modulo operations
  371. { // extra scope for MSVC brokenness w.r.t. for scope
  372. for(unsigned int j = 0; j < short_lag; ++j) {
  373. RealType t = x[j] + x[j+(long_lag-short_lag)];
  374. if(t >= RealType(1))
  375. t -= RealType(1);
  376. x[j] = t;
  377. }
  378. }
  379. for(unsigned int j = short_lag; j < long_lag; ++j) {
  380. RealType t = x[j] + x[j-short_lag];
  381. if(t >= RealType(1))
  382. t -= RealType(1);
  383. x[j] = t;
  384. }
  385. i = 0;
  386. }
  387. /// \endcond
  388. /// \cond show_deprecated
  389. // provided for backwards compatibility
  390. template<class RealType, int w, unsigned int p, unsigned int q>
  391. class lagged_fibonacci_01 : public lagged_fibonacci_01_engine<RealType, w, p, q>
  392. {
  393. typedef lagged_fibonacci_01_engine<RealType, w, p, q> base_type;
  394. public:
  395. lagged_fibonacci_01() {}
  396. BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci_01, boost::uint32_t, val)
  397. { this->seed(val); }
  398. BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(lagged_fibonacci_01, SeedSeq, seq)
  399. { this->seed(seq); }
  400. template<class It>
  401. lagged_fibonacci_01(It& first, It last) : base_type(first, last) {}
  402. };
  403. /// \endcond
  404. namespace detail {
  405. template<class Engine>
  406. struct generator_bits;
  407. template<class RealType, int w, unsigned int p, unsigned int q>
  408. struct generator_bits<lagged_fibonacci_01_engine<RealType, w, p, q> >
  409. {
  410. static std::size_t value() { return w; }
  411. };
  412. template<class RealType, int w, unsigned int p, unsigned int q>
  413. struct generator_bits<lagged_fibonacci_01<RealType, w, p, q> >
  414. {
  415. static std::size_t value() { return w; }
  416. };
  417. }
  418. #ifdef BOOST_RANDOM_DOXYGEN
  419. namespace detail {
  420. /**
  421. * The specializations lagged_fibonacci607 ... lagged_fibonacci44497
  422. * use well tested lags.
  423. *
  424. * See
  425. *
  426. * @blockquote
  427. * "On the Periods of Generalized Fibonacci Recurrences", Richard P. Brent
  428. * Computer Sciences Laboratory Australian National University, December 1992
  429. * @endblockquote
  430. *
  431. * The lags used here can be found in
  432. *
  433. * @blockquote
  434. * "Uniform random number generators for supercomputers", Richard Brent,
  435. * Proc. of Fifth Australian Supercomputer Conference, Melbourne,
  436. * Dec. 1992, pp. 704-706.
  437. * @endblockquote
  438. */
  439. struct lagged_fibonacci_doc {};
  440. }
  441. #endif
  442. /** @copydoc boost::random::detail::lagged_fibonacci_doc */
  443. typedef lagged_fibonacci_01_engine<double, 48, 607, 273> lagged_fibonacci607;
  444. /** @copydoc boost::random::detail::lagged_fibonacci_doc */
  445. typedef lagged_fibonacci_01_engine<double, 48, 1279, 418> lagged_fibonacci1279;
  446. /** @copydoc boost::random::detail::lagged_fibonacci_doc */
  447. typedef lagged_fibonacci_01_engine<double, 48, 2281, 1252> lagged_fibonacci2281;
  448. /** @copydoc boost::random::detail::lagged_fibonacci_doc */
  449. typedef lagged_fibonacci_01_engine<double, 48, 3217, 576> lagged_fibonacci3217;
  450. /** @copydoc boost::random::detail::lagged_fibonacci_doc */
  451. typedef lagged_fibonacci_01_engine<double, 48, 4423, 2098> lagged_fibonacci4423;
  452. /** @copydoc boost::random::detail::lagged_fibonacci_doc */
  453. typedef lagged_fibonacci_01_engine<double, 48, 9689, 5502> lagged_fibonacci9689;
  454. /** @copydoc boost::random::detail::lagged_fibonacci_doc */
  455. typedef lagged_fibonacci_01_engine<double, 48, 19937, 9842> lagged_fibonacci19937;
  456. /** @copydoc boost::random::detail::lagged_fibonacci_doc */
  457. typedef lagged_fibonacci_01_engine<double, 48, 23209, 13470> lagged_fibonacci23209;
  458. /** @copydoc boost::random::detail::lagged_fibonacci_doc */
  459. typedef lagged_fibonacci_01_engine<double, 48, 44497, 21034> lagged_fibonacci44497;
  460. } // namespace random
  461. using random::lagged_fibonacci607;
  462. using random::lagged_fibonacci1279;
  463. using random::lagged_fibonacci2281;
  464. using random::lagged_fibonacci3217;
  465. using random::lagged_fibonacci4423;
  466. using random::lagged_fibonacci9689;
  467. using random::lagged_fibonacci19937;
  468. using random::lagged_fibonacci23209;
  469. using random::lagged_fibonacci44497;
  470. } // namespace boost
  471. #endif // BOOST_RANDOM_LAGGED_FIBONACCI_HPP