int_float_pair.hpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /* boost random/detail/int_float_pair.hpp header file
  2. *
  3. * Copyright Jens Maurer 2000-2001
  4. * Copyright Steven Watanabe 2010-2011
  5. * Distributed under the Boost Software License, Version 1.0. (See
  6. * accompanying file LICENSE_1_0.txt or copy at
  7. * http://www.boost.org/LICENSE_1_0.txt)
  8. *
  9. * See http://www.boost.org for most recent version including documentation.
  10. *
  11. * $Id$
  12. *
  13. */
  14. #ifndef BOOST_RANDOM_DETAIL_INT_FLOAT_PAIR_HPP
  15. #define BOOST_RANDOM_DETAIL_INT_FLOAT_PAIR_HPP
  16. #include <utility>
  17. #include <boost/integer.hpp>
  18. #include <boost/integer/integer_mask.hpp>
  19. #include <boost/type_traits/make_unsigned.hpp>
  20. #include <boost/type_traits/is_integral.hpp>
  21. #include <boost/random/uniform_01.hpp>
  22. #include <boost/random/uniform_int_distribution.hpp>
  23. #include <boost/random/detail/signed_unsigned_tools.hpp>
  24. #include <boost/random/detail/integer_log2.hpp>
  25. namespace boost {
  26. namespace random {
  27. namespace detail {
  28. template<class Engine>
  29. inline typename boost::make_unsigned<typename Engine::result_type>::type
  30. generate_one_digit(Engine& eng, std::size_t bits)
  31. {
  32. typedef typename Engine::result_type base_result;
  33. typedef typename boost::make_unsigned<base_result>::type base_unsigned;
  34. base_unsigned range =
  35. detail::subtract<base_result>()((eng.max)(), (eng.min)());
  36. base_unsigned y0_mask = (base_unsigned(2) << (bits - 1)) - 1;
  37. base_unsigned y0 = (range + 1) & ~y0_mask;
  38. base_unsigned u;
  39. do {
  40. u = detail::subtract<base_result>()(eng(), (eng.min)());
  41. } while(y0 != 0 && u > base_unsigned(y0 - 1));
  42. return u & y0_mask;
  43. }
  44. template<class RealType, std::size_t w, class Engine>
  45. std::pair<RealType, int> generate_int_float_pair(Engine& eng, boost::true_type)
  46. {
  47. typedef typename Engine::result_type base_result;
  48. typedef typename boost::make_unsigned<base_result>::type base_unsigned;
  49. base_unsigned range =
  50. detail::subtract<base_result>()((eng.max)(), (eng.min)());
  51. std::size_t m =
  52. (range == (std::numeric_limits<base_unsigned>::max)()) ?
  53. std::numeric_limits<base_unsigned>::digits :
  54. detail::integer_log2(range + 1);
  55. int bucket = 0;
  56. // process as many full digits as possible into the int part
  57. for(std::size_t i = 0; i < w/m; ++i) {
  58. base_unsigned u = generate_one_digit(eng, m);
  59. bucket = (bucket << m) | u;
  60. }
  61. RealType r;
  62. const std::size_t digits = std::numeric_limits<RealType>::digits;
  63. {
  64. base_unsigned u = generate_one_digit(eng, m);
  65. base_unsigned mask = (base_unsigned(1) << (w%m)) - 1;
  66. bucket = (bucket << (w%m)) | (mask & u);
  67. const RealType mult = RealType(1)/RealType(base_unsigned(1) << (m - w%m));
  68. // zero out unused bits
  69. if (m - w%m > digits) {
  70. u &= ~(base_unsigned(1) << (m - digits));
  71. }
  72. r = RealType(u >> (w%m)) * mult;
  73. }
  74. for(std::size_t i = m - w%m; i + m < digits; i += m) {
  75. base_unsigned u = generate_one_digit(eng, m);
  76. r += u;
  77. r *= RealType(0.5)/RealType(base_unsigned(1) << (m - 1));
  78. }
  79. if (m - w%m < digits)
  80. {
  81. const std::size_t remaining = (digits - m + w%m) % m;
  82. base_unsigned u = generate_one_digit(eng, m);
  83. r += u & ((base_unsigned(2) << (remaining - 1)) - 1);
  84. const RealType mult = RealType(0.5)/RealType(base_unsigned(1) << (remaining - 1));
  85. r *= mult;
  86. }
  87. return std::make_pair(r, bucket);
  88. }
  89. template<class RealType, std::size_t w, class Engine>
  90. inline std::pair<RealType, int> generate_int_float_pair(Engine& eng, boost::false_type)
  91. {
  92. int bucket = uniform_int_distribution<>(0, (1 << w) - 1)(eng);
  93. RealType r = uniform_01<RealType>()(eng);
  94. return std::make_pair(r, bucket);
  95. }
  96. template<class RealType, std::size_t w, class Engine>
  97. inline std::pair<RealType, int> generate_int_float_pair(Engine& eng)
  98. {
  99. typedef typename Engine::result_type base_result;
  100. return generate_int_float_pair<RealType, w>(eng,
  101. boost::is_integral<base_result>());
  102. }
  103. } // namespace detail
  104. } // namespace random
  105. } // namespace boost
  106. #endif // BOOST_RANDOM_DETAIL_INT_FLOAT_PAIR_HPP