/src/contrib/boost/random/subtract_with_carry.hpp

http://pythonocc.googlecode.com/ · C++ Header · 465 lines · 348 code · 48 blank · 69 comment · 59 complexity · 868dac82b4bb653f9ab6b81f44c287a3 MD5 · raw file

  1. /* boost random/subtract_with_carry.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: subtract_with_carry.hpp 60755 2010-03-22 00:45:06Z steven_watanabe $
  11. *
  12. * Revision history
  13. * 2002-03-02 created
  14. */
  15. #ifndef BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP
  16. #define BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP
  17. #include <boost/config/no_tr1/cmath.hpp>
  18. #include <iostream>
  19. #include <algorithm> // std::equal
  20. #include <stdexcept>
  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/static_assert.hpp>
  26. #include <boost/detail/workaround.hpp>
  27. #include <boost/random/detail/config.hpp>
  28. #include <boost/random/detail/seed.hpp>
  29. #include <boost/random/linear_congruential.hpp>
  30. namespace boost {
  31. namespace random {
  32. #if BOOST_WORKAROUND(_MSC_FULL_VER, BOOST_TESTED_AT(13102292)) && BOOST_MSVC > 1300
  33. # define BOOST_RANDOM_EXTRACT_SWC_01
  34. #endif
  35. #if defined(__APPLE_CC__) && defined(__GNUC__) && (__GNUC__ == 3) && (__GNUC_MINOR__ <= 3)
  36. # define BOOST_RANDOM_EXTRACT_SWC_01
  37. #endif
  38. # ifdef BOOST_RANDOM_EXTRACT_SWC_01
  39. namespace detail
  40. {
  41. template <class IStream, class SubtractWithCarry, class RealType>
  42. void extract_subtract_with_carry_01(
  43. IStream& is
  44. , SubtractWithCarry& f
  45. , RealType& carry
  46. , RealType* x
  47. , RealType modulus)
  48. {
  49. RealType value;
  50. for(unsigned int j = 0; j < f.long_lag; ++j) {
  51. is >> value >> std::ws;
  52. x[j] = value / modulus;
  53. }
  54. is >> value >> std::ws;
  55. carry = value / modulus;
  56. }
  57. }
  58. # endif
  59. /**
  60. * Instantiations of @c subtract_with_carry model a
  61. * \pseudo_random_number_generator. The algorithm is
  62. * described in
  63. *
  64. * @blockquote
  65. * "A New Class of Random Number Generators", George
  66. * Marsaglia and Arif Zaman, Annals of Applied Probability,
  67. * Volume 1, Number 3 (1991), 462-480.
  68. * @endblockquote
  69. */
  70. template<class IntType, IntType m, unsigned int s, unsigned int r,
  71. IntType val>
  72. class subtract_with_carry
  73. {
  74. public:
  75. typedef IntType result_type;
  76. BOOST_STATIC_CONSTANT(bool, has_fixed_range = true);
  77. BOOST_STATIC_CONSTANT(result_type, min_value = 0);
  78. BOOST_STATIC_CONSTANT(result_type, max_value = m-1);
  79. BOOST_STATIC_CONSTANT(result_type, modulus = m);
  80. BOOST_STATIC_CONSTANT(unsigned int, long_lag = r);
  81. BOOST_STATIC_CONSTANT(unsigned int, short_lag = s);
  82. subtract_with_carry() {
  83. // MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope
  84. #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
  85. BOOST_STATIC_ASSERT(std::numeric_limits<result_type>::is_signed);
  86. BOOST_STATIC_ASSERT(std::numeric_limits<result_type>::is_integer);
  87. #endif
  88. seed();
  89. }
  90. BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry, uint32_t, value)
  91. { seed(value); }
  92. BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(subtract_with_carry, Generator, gen)
  93. { seed(gen); }
  94. template<class It> subtract_with_carry(It& first, It last) { seed(first,last); }
  95. // compiler-generated copy ctor and assignment operator are fine
  96. void seed() { seed(19780503u); }
  97. BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry, uint32_t, value)
  98. {
  99. random::linear_congruential<int32_t, 40014, 0, 2147483563, 0> intgen(value);
  100. seed(intgen);
  101. }
  102. // For GCC, moving this function out-of-line prevents inlining, which may
  103. // reduce overall object code size. However, MSVC does not grok
  104. // out-of-line template member functions.
  105. BOOST_RANDOM_DETAIL_GENERATOR_SEED(subtract_with_carry, Generator, gen)
  106. {
  107. // I could have used std::generate_n, but it takes "gen" by value
  108. for(unsigned int j = 0; j < long_lag; ++j)
  109. x[j] = gen() % modulus;
  110. carry = (x[long_lag-1] == 0);
  111. k = 0;
  112. }
  113. template<class It>
  114. void seed(It& first, It last)
  115. {
  116. unsigned int j;
  117. for(j = 0; j < long_lag && first != last; ++j, ++first)
  118. x[j] = *first % modulus;
  119. if(first == last && j < long_lag)
  120. throw std::invalid_argument("subtract_with_carry::seed");
  121. carry = (x[long_lag-1] == 0);
  122. k = 0;
  123. }
  124. result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return min_value; }
  125. result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return max_value; }
  126. result_type operator()()
  127. {
  128. int short_index = k - short_lag;
  129. if(short_index < 0)
  130. short_index += long_lag;
  131. IntType delta;
  132. if (x[short_index] >= x[k] + carry) {
  133. // x(n) >= 0
  134. delta = x[short_index] - (x[k] + carry);
  135. carry = 0;
  136. } else {
  137. // x(n) < 0
  138. delta = modulus - x[k] - carry + x[short_index];
  139. carry = 1;
  140. }
  141. x[k] = delta;
  142. ++k;
  143. if(k >= long_lag)
  144. k = 0;
  145. return delta;
  146. }
  147. public:
  148. static bool validation(result_type x) { return x == val; }
  149. #ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
  150. #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS
  151. template<class CharT, class Traits>
  152. friend std::basic_ostream<CharT,Traits>&
  153. operator<<(std::basic_ostream<CharT,Traits>& os,
  154. const subtract_with_carry& f)
  155. {
  156. for(unsigned int j = 0; j < f.long_lag; ++j)
  157. os << f.compute(j) << " ";
  158. os << f.carry << " ";
  159. return os;
  160. }
  161. template<class CharT, class Traits>
  162. friend std::basic_istream<CharT,Traits>&
  163. operator>>(std::basic_istream<CharT,Traits>& is, subtract_with_carry& f)
  164. {
  165. for(unsigned int j = 0; j < f.long_lag; ++j)
  166. is >> f.x[j] >> std::ws;
  167. is >> f.carry >> std::ws;
  168. f.k = 0;
  169. return is;
  170. }
  171. #endif
  172. friend bool operator==(const subtract_with_carry& x, const subtract_with_carry& y)
  173. {
  174. for(unsigned int j = 0; j < r; ++j)
  175. if(x.compute(j) != y.compute(j))
  176. return false;
  177. return true;
  178. }
  179. friend bool operator!=(const subtract_with_carry& x, const subtract_with_carry& y)
  180. { return !(x == y); }
  181. #else
  182. // Use a member function; Streamable concept not supported.
  183. bool operator==(const subtract_with_carry& rhs) const
  184. {
  185. for(unsigned int j = 0; j < r; ++j)
  186. if(compute(j) != rhs.compute(j))
  187. return false;
  188. return true;
  189. }
  190. bool operator!=(const subtract_with_carry& rhs) const
  191. { return !(*this == rhs); }
  192. #endif
  193. private:
  194. /// \cond hide_private_members
  195. // returns x(i-r+index), where index is in 0..r-1
  196. IntType compute(unsigned int index) const
  197. {
  198. return x[(k+index) % long_lag];
  199. }
  200. /// \endcond
  201. // state representation; next output (state) is x(i)
  202. // x[0] ... x[k] x[k+1] ... x[long_lag-1] represents
  203. // x(i-k) ... x(i) x(i+1) ... x(i-k+long_lag-1)
  204. // speed: base: 20-25 nsec
  205. // ranlux_4: 230 nsec, ranlux_7: 430 nsec, ranlux_14: 810 nsec
  206. // This state representation makes operator== and save/restore more
  207. // difficult, because we've already computed "too much" and thus
  208. // have to undo some steps to get at x(i-r) etc.
  209. // state representation: next output (state) is x(i)
  210. // x[0] ... x[k] x[k+1] ... x[long_lag-1] represents
  211. // x(i-k) ... x(i) x(i-long_lag+1) ... x(i-k-1)
  212. // speed: base 28 nsec
  213. // ranlux_4: 370 nsec, ranlux_7: 688 nsec, ranlux_14: 1343 nsec
  214. IntType x[long_lag];
  215. unsigned int k;
  216. int carry;
  217. };
  218. #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
  219. // A definition is required even for integral static constants
  220. template<class IntType, IntType m, unsigned int s, unsigned int r, IntType val>
  221. const bool subtract_with_carry<IntType, m, s, r, val>::has_fixed_range;
  222. template<class IntType, IntType m, unsigned int s, unsigned int r, IntType val>
  223. const IntType subtract_with_carry<IntType, m, s, r, val>::min_value;
  224. template<class IntType, IntType m, unsigned int s, unsigned int r, IntType val>
  225. const IntType subtract_with_carry<IntType, m, s, r, val>::max_value;
  226. template<class IntType, IntType m, unsigned int s, unsigned int r, IntType val>
  227. const IntType subtract_with_carry<IntType, m, s, r, val>::modulus;
  228. template<class IntType, IntType m, unsigned int s, unsigned int r, IntType val>
  229. const unsigned int subtract_with_carry<IntType, m, s, r, val>::long_lag;
  230. template<class IntType, IntType m, unsigned int s, unsigned int r, IntType val>
  231. const unsigned int subtract_with_carry<IntType, m, s, r, val>::short_lag;
  232. #endif
  233. // use a floating-point representation to produce values in [0..1)
  234. /** @copydoc boost::random::subtract_with_carry */
  235. template<class RealType, int w, unsigned int s, unsigned int r, int val=0>
  236. class subtract_with_carry_01
  237. {
  238. public:
  239. typedef RealType result_type;
  240. BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
  241. BOOST_STATIC_CONSTANT(int, word_size = w);
  242. BOOST_STATIC_CONSTANT(unsigned int, long_lag = r);
  243. BOOST_STATIC_CONSTANT(unsigned int, short_lag = s);
  244. #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
  245. BOOST_STATIC_ASSERT(!std::numeric_limits<result_type>::is_integer);
  246. #endif
  247. subtract_with_carry_01() { init_modulus(); seed(); }
  248. explicit subtract_with_carry_01(uint32_t value)
  249. { init_modulus(); seed(value); }
  250. template<class It> subtract_with_carry_01(It& first, It last)
  251. { init_modulus(); seed(first,last); }
  252. private:
  253. /// \cond hide_private_members
  254. void init_modulus()
  255. {
  256. #ifndef BOOST_NO_STDC_NAMESPACE
  257. // allow for Koenig lookup
  258. using std::pow;
  259. #endif
  260. _modulus = pow(RealType(2), word_size);
  261. }
  262. /// \endcond hide_private_members
  263. public:
  264. // compiler-generated copy ctor and assignment operator are fine
  265. void seed(uint32_t value = 19780503u)
  266. {
  267. #ifndef BOOST_NO_STDC_NAMESPACE
  268. // allow for Koenig lookup
  269. using std::fmod;
  270. #endif
  271. random::linear_congruential<int32_t, 40014, 0, 2147483563, 0> gen(value);
  272. unsigned long array[(w+31)/32 * long_lag];
  273. for(unsigned int j = 0; j < sizeof(array)/sizeof(unsigned long); ++j)
  274. array[j] = gen();
  275. unsigned long * start = array;
  276. seed(start, array + sizeof(array)/sizeof(unsigned long));
  277. }
  278. template<class It>
  279. void seed(It& first, It last)
  280. {
  281. #ifndef BOOST_NO_STDC_NAMESPACE
  282. // allow for Koenig lookup
  283. using std::fmod;
  284. using std::pow;
  285. #endif
  286. unsigned long mask = ~((~0u) << (w%32)); // now lowest (w%32) bits set
  287. RealType two32 = pow(RealType(2), 32);
  288. unsigned int j;
  289. for(j = 0; j < long_lag && first != last; ++j) {
  290. x[j] = RealType(0);
  291. for(int i = 0; i < w/32 && first != last; ++i, ++first)
  292. x[j] += *first / pow(two32,i+1);
  293. if(first != last && mask != 0) {
  294. x[j] += fmod((*first & mask) / _modulus, RealType(1));
  295. ++first;
  296. }
  297. }
  298. if(first == last && j < long_lag)
  299. throw std::invalid_argument("subtract_with_carry_01::seed");
  300. carry = (x[long_lag-1] ? 0 : 1 / _modulus);
  301. k = 0;
  302. }
  303. result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(0); }
  304. result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(1); }
  305. result_type operator()()
  306. {
  307. int short_index = k - short_lag;
  308. if(short_index < 0)
  309. short_index += long_lag;
  310. RealType delta = x[short_index] - x[k] - carry;
  311. if(delta < 0) {
  312. delta += RealType(1);
  313. carry = RealType(1)/_modulus;
  314. } else {
  315. carry = 0;
  316. }
  317. x[k] = delta;
  318. ++k;
  319. if(k >= long_lag)
  320. k = 0;
  321. return delta;
  322. }
  323. static bool validation(result_type x)
  324. { return x == val/pow(RealType(2), word_size); }
  325. #ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
  326. #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS
  327. template<class CharT, class Traits>
  328. friend std::basic_ostream<CharT,Traits>&
  329. operator<<(std::basic_ostream<CharT,Traits>& os,
  330. const subtract_with_carry_01& f)
  331. {
  332. #ifndef BOOST_NO_STDC_NAMESPACE
  333. // allow for Koenig lookup
  334. using std::pow;
  335. #endif
  336. std::ios_base::fmtflags oldflags = os.flags(os.dec | os.fixed | os.left);
  337. for(unsigned int j = 0; j < f.long_lag; ++j)
  338. os << (f.compute(j) * f._modulus) << " ";
  339. os << (f.carry * f._modulus);
  340. os.flags(oldflags);
  341. return os;
  342. }
  343. template<class CharT, class Traits>
  344. friend std::basic_istream<CharT,Traits>&
  345. operator>>(std::basic_istream<CharT,Traits>& is, subtract_with_carry_01& f)
  346. {
  347. # ifdef BOOST_RANDOM_EXTRACT_SWC_01
  348. detail::extract_subtract_with_carry_01(is, f, f.carry, f.x, f._modulus);
  349. # else
  350. // MSVC (up to 7.1) and Borland (up to 5.64) don't handle the template type
  351. // parameter "RealType" available from the class template scope, so use
  352. // the member typedef
  353. typename subtract_with_carry_01::result_type value;
  354. for(unsigned int j = 0; j < long_lag; ++j) {
  355. is >> value >> std::ws;
  356. f.x[j] = value / f._modulus;
  357. }
  358. is >> value >> std::ws;
  359. f.carry = value / f._modulus;
  360. # endif
  361. f.k = 0;
  362. return is;
  363. }
  364. #endif
  365. friend bool operator==(const subtract_with_carry_01& x,
  366. const subtract_with_carry_01& y)
  367. {
  368. for(unsigned int j = 0; j < r; ++j)
  369. if(x.compute(j) != y.compute(j))
  370. return false;
  371. return true;
  372. }
  373. friend bool operator!=(const subtract_with_carry_01& x,
  374. const subtract_with_carry_01& y)
  375. { return !(x == y); }
  376. #else
  377. // Use a member function; Streamable concept not supported.
  378. bool operator==(const subtract_with_carry_01& rhs) const
  379. {
  380. for(unsigned int j = 0; j < r; ++j)
  381. if(compute(j) != rhs.compute(j))
  382. return false;
  383. return true;
  384. }
  385. bool operator!=(const subtract_with_carry_01& rhs) const
  386. { return !(*this == rhs); }
  387. #endif
  388. private:
  389. /// \cond hide_private_members
  390. RealType compute(unsigned int index) const;
  391. /// \endcond
  392. unsigned int k;
  393. RealType carry;
  394. RealType x[long_lag];
  395. RealType _modulus;
  396. };
  397. #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
  398. // A definition is required even for integral static constants
  399. template<class RealType, int w, unsigned int s, unsigned int r, int val>
  400. const bool subtract_with_carry_01<RealType, w, s, r, val>::has_fixed_range;
  401. template<class RealType, int w, unsigned int s, unsigned int r, int val>
  402. const int subtract_with_carry_01<RealType, w, s, r, val>::word_size;
  403. template<class RealType, int w, unsigned int s, unsigned int r, int val>
  404. const unsigned int subtract_with_carry_01<RealType, w, s, r, val>::long_lag;
  405. template<class RealType, int w, unsigned int s, unsigned int r, int val>
  406. const unsigned int subtract_with_carry_01<RealType, w, s, r, val>::short_lag;
  407. #endif
  408. /// \cond hide_private_members
  409. template<class RealType, int w, unsigned int s, unsigned int r, int val>
  410. RealType subtract_with_carry_01<RealType, w, s, r, val>::compute(unsigned int index) const
  411. {
  412. return x[(k+index) % long_lag];
  413. }
  414. /// \endcond
  415. } // namespace random
  416. } // namespace boost
  417. #endif // BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP