int_float_pair.hpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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. #include <boost/mpl/bool.hpp>
  26. namespace boost {
  27. namespace random {
  28. namespace detail {
  29. template<class Engine>
  30. inline typename boost::make_unsigned<typename Engine::result_type>::type
  31. generate_one_digit(Engine& eng, std::size_t bits)
  32. {
  33. typedef typename Engine::result_type base_result;
  34. typedef typename boost::make_unsigned<base_result>::type base_unsigned;
  35. base_unsigned range =
  36. detail::subtract<base_result>()((eng.max)(), (eng.min)());
  37. base_unsigned y0_mask = (base_unsigned(2) << (bits - 1)) - 1;
  38. base_unsigned y0 = (range + 1) & ~y0_mask;
  39. base_unsigned u;
  40. do {
  41. u = detail::subtract<base_result>()(eng(), (eng.min)());
  42. } while(y0 != 0 && u > base_unsigned(y0 - 1));
  43. return u & y0_mask;
  44. }
  45. template<class RealType, std::size_t w, class Engine>
  46. std::pair<RealType, int> generate_int_float_pair(Engine& eng, boost::mpl::true_)
  47. {
  48. typedef typename Engine::result_type base_result;
  49. typedef typename boost::make_unsigned<base_result>::type base_unsigned;
  50. base_unsigned range =
  51. detail::subtract<base_result>()((eng.max)(), (eng.min)());
  52. std::size_t m =
  53. (range == (std::numeric_limits<base_unsigned>::max)()) ?
  54. std::numeric_limits<base_unsigned>::digits :
  55. detail::integer_log2(range + 1);
  56. int bucket = 0;
  57. // process as many full digits as possible into the int part
  58. for(std::size_t i = 0; i < w/m; ++i) {
  59. base_unsigned u = generate_one_digit(eng, m);
  60. bucket = (bucket << m) | u;
  61. }
  62. RealType r;
  63. const std::size_t digits = std::numeric_limits<RealType>::digits;
  64. {
  65. base_unsigned u = generate_one_digit(eng, m);
  66. base_unsigned mask = (base_unsigned(1) << (w%m)) - 1;
  67. bucket = (bucket << (w%m)) | (mask & u);
  68. const RealType mult = RealType(1)/RealType(base_unsigned(1) << (m - w%m));
  69. // zero out unused bits
  70. if (m - w%m > digits) {
  71. u &= ~(base_unsigned(1) << (m - digits));
  72. }
  73. r = RealType(u >> (w%m)) * mult;
  74. }
  75. for(std::size_t i = m - w%m; i + m < digits; ++i) {
  76. base_unsigned u = generate_one_digit(eng, m);
  77. r += u;
  78. r *= RealType(0.5)/RealType(base_unsigned(1) << (m - 1));
  79. }
  80. if (m - w%m < digits)
  81. {
  82. const std::size_t remaining = (digits - m + w%m) % m;
  83. base_unsigned u = generate_one_digit(eng, m);
  84. r += u & ((base_unsigned(2) << (remaining - 1)) - 1);
  85. const RealType mult = RealType(0.5)/RealType(base_unsigned(1) << (remaining - 1));
  86. r *= mult;
  87. }
  88. return std::make_pair(r, bucket);
  89. }
  90. template<class RealType, std::size_t w, class Engine>
  91. inline std::pair<RealType, int> generate_int_float_pair(Engine& eng, boost::mpl::false_)
  92. {
  93. int bucket = uniform_int_distribution<>(0, (1 << w) - 1)(eng);
  94. RealType r = uniform_01<RealType>()(eng);
  95. return std::make_pair(r, bucket);
  96. }
  97. template<class RealType, std::size_t w, class Engine>
  98. inline std::pair<RealType, int> generate_int_float_pair(Engine& eng)
  99. {
  100. typedef typename Engine::result_type base_result;
  101. return generate_int_float_pair<RealType, w>(eng,
  102. boost::is_integral<base_result>());
  103. }
  104. } // namespace detail
  105. } // namespace random
  106. } // namespace boost
  107. #endif // BOOST_RANDOM_DETAIL_INT_FLOAT_PAIR_HPP