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