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
generate_one_digit(Engine & eng,std::size_t bits)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>
generate_int_float_pair(Engine & eng,boost::mpl::true_)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>
generate_int_float_pair(Engine & eng,boost::mpl::false_)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>
generate_int_float_pair(Engine & eng)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