williamr@2
|
1 |
/* boost random/uniform_int.hpp header file
|
williamr@2
|
2 |
*
|
williamr@2
|
3 |
* Copyright Jens Maurer 2000-2001
|
williamr@2
|
4 |
* Distributed under the Boost Software License, Version 1.0. (See
|
williamr@2
|
5 |
* accompanying file LICENSE_1_0.txt or copy at
|
williamr@2
|
6 |
* http://www.boost.org/LICENSE_1_0.txt)
|
williamr@2
|
7 |
*
|
williamr@2
|
8 |
* See http://www.boost.org for most recent version including documentation.
|
williamr@2
|
9 |
*
|
williamr@2
|
10 |
* $Id: uniform_int.hpp,v 1.27 2004/07/27 03:43:32 dgregor Exp $
|
williamr@2
|
11 |
*
|
williamr@2
|
12 |
* Revision history
|
williamr@2
|
13 |
* 2001-04-08 added min<max assertion (N. Becker)
|
williamr@2
|
14 |
* 2001-02-18 moved to individual header files
|
williamr@2
|
15 |
*/
|
williamr@2
|
16 |
|
williamr@2
|
17 |
#ifndef BOOST_RANDOM_UNIFORM_INT_HPP
|
williamr@2
|
18 |
#define BOOST_RANDOM_UNIFORM_INT_HPP
|
williamr@2
|
19 |
|
williamr@2
|
20 |
#include <cassert>
|
williamr@2
|
21 |
#include <iostream>
|
williamr@2
|
22 |
#include <boost/config.hpp>
|
williamr@2
|
23 |
#include <boost/limits.hpp>
|
williamr@2
|
24 |
#include <boost/static_assert.hpp>
|
williamr@2
|
25 |
#include <boost/detail/workaround.hpp>
|
williamr@2
|
26 |
#include <boost/random/uniform_smallint.hpp>
|
williamr@2
|
27 |
#include <boost/random/detail/signed_unsigned_compare.hpp>
|
williamr@2
|
28 |
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
williamr@2
|
29 |
#include <boost/type_traits/is_float.hpp>
|
williamr@2
|
30 |
#endif
|
williamr@2
|
31 |
|
williamr@2
|
32 |
namespace boost {
|
williamr@2
|
33 |
|
williamr@2
|
34 |
// uniform integer distribution on [min, max]
|
williamr@2
|
35 |
template<class IntType = int>
|
williamr@2
|
36 |
class uniform_int
|
williamr@2
|
37 |
{
|
williamr@2
|
38 |
public:
|
williamr@2
|
39 |
typedef IntType input_type;
|
williamr@2
|
40 |
typedef IntType result_type;
|
williamr@2
|
41 |
|
williamr@2
|
42 |
explicit uniform_int(IntType min = 0, IntType max = 9)
|
williamr@2
|
43 |
: _min(min), _max(max)
|
williamr@2
|
44 |
{
|
williamr@2
|
45 |
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
williamr@2
|
46 |
// MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope
|
williamr@2
|
47 |
BOOST_STATIC_ASSERT(std::numeric_limits<IntType>::is_integer);
|
williamr@2
|
48 |
#endif
|
williamr@2
|
49 |
assert(min <= max);
|
williamr@2
|
50 |
init();
|
williamr@2
|
51 |
}
|
williamr@2
|
52 |
|
williamr@2
|
53 |
result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _min; }
|
williamr@2
|
54 |
result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _max; }
|
williamr@2
|
55 |
void reset() { }
|
williamr@2
|
56 |
|
williamr@2
|
57 |
// can't have member function templates out-of-line due to MSVC bugs
|
williamr@2
|
58 |
template<class Engine>
|
williamr@2
|
59 |
result_type operator()(Engine& eng)
|
williamr@2
|
60 |
{
|
williamr@2
|
61 |
typedef typename Engine::result_type base_result;
|
williamr@2
|
62 |
base_result bmin = (eng.min)();
|
williamr@2
|
63 |
base_result brange = (eng.max)() - (eng.min)();
|
williamr@2
|
64 |
|
williamr@2
|
65 |
if(_range == 0) {
|
williamr@2
|
66 |
return _min;
|
williamr@2
|
67 |
} else if(random::equal_signed_unsigned(brange, _range)) {
|
williamr@2
|
68 |
// this will probably never happen in real life
|
williamr@2
|
69 |
// basically nothing to do; just take care we don't overflow / underflow
|
williamr@2
|
70 |
return static_cast<result_type>(eng() - bmin) + _min;
|
williamr@2
|
71 |
} else if(random::lessthan_signed_unsigned(brange, _range)) {
|
williamr@2
|
72 |
// use rejection method to handle things like 0..3 --> 0..4
|
williamr@2
|
73 |
for(;;) {
|
williamr@2
|
74 |
// concatenate several invocations of the base RNG
|
williamr@2
|
75 |
// take extra care to avoid overflows
|
williamr@2
|
76 |
result_type limit;
|
williamr@2
|
77 |
if(_range == (std::numeric_limits<result_type>::max)()) {
|
williamr@2
|
78 |
limit = _range/(result_type(brange)+1);
|
williamr@2
|
79 |
if(_range % result_type(brange)+1 == result_type(brange))
|
williamr@2
|
80 |
++limit;
|
williamr@2
|
81 |
} else {
|
williamr@2
|
82 |
limit = (_range+1)/(result_type(brange)+1);
|
williamr@2
|
83 |
}
|
williamr@2
|
84 |
// We consider "result" as expressed to base (brange+1):
|
williamr@2
|
85 |
// For every power of (brange+1), we determine a random factor
|
williamr@2
|
86 |
result_type result = result_type(0);
|
williamr@2
|
87 |
result_type mult = result_type(1);
|
williamr@2
|
88 |
while(mult <= limit) {
|
williamr@2
|
89 |
result += (eng() - bmin) * mult;
|
williamr@2
|
90 |
mult *= result_type(brange)+result_type(1);
|
williamr@2
|
91 |
}
|
williamr@2
|
92 |
if(mult == limit)
|
williamr@2
|
93 |
// _range+1 is an integer power of brange+1: no rejections required
|
williamr@2
|
94 |
return result;
|
williamr@2
|
95 |
// _range/mult < brange+1 -> no endless loop
|
williamr@2
|
96 |
result += uniform_int<result_type>(0, _range/mult)(eng) * mult;
|
williamr@2
|
97 |
if(result <= _range)
|
williamr@2
|
98 |
return result + _min;
|
williamr@2
|
99 |
}
|
williamr@2
|
100 |
} else { // brange > range
|
williamr@2
|
101 |
if(brange / _range > 4 /* quantization_cutoff */ ) {
|
williamr@2
|
102 |
// the new range is vastly smaller than the source range,
|
williamr@2
|
103 |
// so quantization effects are not relevant
|
williamr@2
|
104 |
return boost::uniform_smallint<result_type>(_min, _max)(eng);
|
williamr@2
|
105 |
} else {
|
williamr@2
|
106 |
// use rejection method to handle cases like 0..5 -> 0..4
|
williamr@2
|
107 |
for(;;) {
|
williamr@2
|
108 |
base_result result = eng() - bmin;
|
williamr@2
|
109 |
// result and range are non-negative, and result is possibly larger
|
williamr@2
|
110 |
// than range, so the cast is safe
|
williamr@2
|
111 |
if(result <= static_cast<base_result>(_range))
|
williamr@2
|
112 |
return result + _min;
|
williamr@2
|
113 |
}
|
williamr@2
|
114 |
}
|
williamr@2
|
115 |
}
|
williamr@2
|
116 |
}
|
williamr@2
|
117 |
|
williamr@2
|
118 |
#if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
williamr@2
|
119 |
template<class CharT, class Traits>
|
williamr@2
|
120 |
friend std::basic_ostream<CharT,Traits>&
|
williamr@2
|
121 |
operator<<(std::basic_ostream<CharT,Traits>& os, const uniform_int& ud)
|
williamr@2
|
122 |
{
|
williamr@2
|
123 |
os << ud._min << " " << ud._max;
|
williamr@2
|
124 |
return os;
|
williamr@2
|
125 |
}
|
williamr@2
|
126 |
|
williamr@2
|
127 |
template<class CharT, class Traits>
|
williamr@2
|
128 |
friend std::basic_istream<CharT,Traits>&
|
williamr@2
|
129 |
operator>>(std::basic_istream<CharT,Traits>& is, uniform_int& ud)
|
williamr@2
|
130 |
{
|
williamr@2
|
131 |
# if BOOST_WORKAROUND(_MSC_FULL_VER, BOOST_TESTED_AT(13102292)) && BOOST_MSVC > 1300
|
williamr@2
|
132 |
return detail::extract_uniform_int(is, ud, ud.impl);
|
williamr@2
|
133 |
# else
|
williamr@2
|
134 |
is >> std::ws >> ud._min >> std::ws >> ud._max;
|
williamr@2
|
135 |
ud.init();
|
williamr@2
|
136 |
return is;
|
williamr@2
|
137 |
# endif
|
williamr@2
|
138 |
}
|
williamr@2
|
139 |
#endif
|
williamr@2
|
140 |
|
williamr@2
|
141 |
private:
|
williamr@2
|
142 |
void init()
|
williamr@2
|
143 |
{
|
williamr@2
|
144 |
_range = _max - _min;
|
williamr@2
|
145 |
}
|
williamr@2
|
146 |
|
williamr@2
|
147 |
result_type _min, _max, _range;
|
williamr@2
|
148 |
};
|
williamr@2
|
149 |
|
williamr@2
|
150 |
} // namespace boost
|
williamr@2
|
151 |
|
williamr@2
|
152 |
#endif // BOOST_RANDOM_UNIFORM_INT_HPP
|