|
1 /* boost random/uniform_smallint.hpp header file |
|
2 * |
|
3 * Copyright Jens Maurer 2000-2001 |
|
4 * Distributed under the Boost Software License, Version 1.0. (See |
|
5 * accompanying file LICENSE_1_0.txt or copy at |
|
6 * http://www.boost.org/LICENSE_1_0.txt) |
|
7 * |
|
8 * See http://www.boost.org for most recent version including documentation. |
|
9 * |
|
10 * $Id: uniform_smallint.hpp,v 1.29 2004/07/27 03:43:32 dgregor Exp $ |
|
11 * |
|
12 * Revision history |
|
13 * 2001-04-08 added min<max assertion (N. Becker) |
|
14 * 2001-02-18 moved to individual header files |
|
15 */ |
|
16 |
|
17 #ifndef BOOST_RANDOM_UNIFORM_SMALLINT_HPP |
|
18 #define BOOST_RANDOM_UNIFORM_SMALLINT_HPP |
|
19 |
|
20 #include <cassert> |
|
21 #include <iostream> |
|
22 #include <boost/config.hpp> |
|
23 #include <boost/limits.hpp> |
|
24 #include <boost/static_assert.hpp> |
|
25 #include <boost/random/uniform_01.hpp> |
|
26 #include <boost/detail/workaround.hpp> |
|
27 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS |
|
28 #include <boost/type_traits/is_float.hpp> |
|
29 #endif |
|
30 |
|
31 |
|
32 namespace boost { |
|
33 |
|
34 // uniform integer distribution on a small range [min, max] |
|
35 |
|
36 namespace detail { |
|
37 |
|
38 template <class InputStream, class UniformInt, class Impl> |
|
39 InputStream& extract_uniform_int(InputStream& is, UniformInt& ud, Impl& impl) |
|
40 { |
|
41 typename UniformInt::result_type min, max; |
|
42 is >> std::ws >> min >> std::ws >> max; |
|
43 impl.set(min, max); |
|
44 return is; |
|
45 } |
|
46 |
|
47 template<class UniformRandomNumberGenerator, class IntType> |
|
48 struct uniform_smallint_integer |
|
49 { |
|
50 public: |
|
51 typedef UniformRandomNumberGenerator base_type; |
|
52 typedef IntType result_type; |
|
53 |
|
54 uniform_smallint_integer(base_type & rng, IntType min, IntType max) |
|
55 : _rng(&rng) |
|
56 { set(min, max); } |
|
57 |
|
58 void set(result_type min, result_type max); |
|
59 |
|
60 result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _min; } |
|
61 result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _max; } |
|
62 base_type& base() const { return *_rng; } |
|
63 |
|
64 result_type operator()() |
|
65 { |
|
66 // we must not use the low bits here, because LCGs get very bad then |
|
67 return (((*_rng)() - (_rng->min)()) / _factor) % _range + _min; |
|
68 } |
|
69 |
|
70 private: |
|
71 typedef typename base_type::result_type base_result; |
|
72 base_type * _rng; |
|
73 IntType _min, _max; |
|
74 base_result _range; |
|
75 int _factor; |
|
76 }; |
|
77 |
|
78 template<class UniformRandomNumberGenerator, class IntType> |
|
79 void uniform_smallint_integer<UniformRandomNumberGenerator, IntType>:: |
|
80 set(result_type min, result_type max) |
|
81 { |
|
82 _min = min; |
|
83 _max = max; |
|
84 assert(min < max); |
|
85 |
|
86 _range = static_cast<base_result>(_max-_min)+1; |
|
87 base_result _factor = 1; |
|
88 |
|
89 // LCGs get bad when only taking the low bits. |
|
90 // (probably put this logic into a partial template specialization) |
|
91 // Check how many low bits we can ignore before we get too much |
|
92 // quantization error. |
|
93 base_result r_base = (_rng->max)() - (_rng->min)(); |
|
94 if(r_base == (std::numeric_limits<base_result>::max)()) { |
|
95 _factor = 2; |
|
96 r_base /= 2; |
|
97 } |
|
98 r_base += 1; |
|
99 if(r_base % _range == 0) { |
|
100 // No quantization effects, good |
|
101 _factor = r_base / _range; |
|
102 } else { |
|
103 // carefully avoid overflow; pessimizing heree |
|
104 for( ; r_base/_range/32 >= _range; _factor *= 2) |
|
105 r_base /= 2; |
|
106 } |
|
107 } |
|
108 |
|
109 template<class UniformRandomNumberGenerator, class IntType> |
|
110 class uniform_smallint_float |
|
111 { |
|
112 public: |
|
113 typedef UniformRandomNumberGenerator base_type; |
|
114 typedef IntType result_type; |
|
115 |
|
116 uniform_smallint_float(base_type & rng, IntType min, IntType max) |
|
117 : _rng(rng) |
|
118 { |
|
119 // MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope |
|
120 #if !defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) && !(defined(BOOST_MSVC) && BOOST_MSVC <= 1300) |
|
121 BOOST_STATIC_ASSERT(std::numeric_limits<IntType>::is_integer); |
|
122 BOOST_STATIC_ASSERT(!std::numeric_limits<typename base_type::result_type>::is_integer); |
|
123 #endif |
|
124 |
|
125 assert(min < max); |
|
126 set(min, max); |
|
127 } |
|
128 |
|
129 void set(result_type min, result_type max) |
|
130 { |
|
131 _min = min; |
|
132 _max = max; |
|
133 _range = static_cast<base_result>(_max-_min)+1; |
|
134 } |
|
135 |
|
136 result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _min; } |
|
137 result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _max; } |
|
138 base_type& base() const { return _rng.base(); } |
|
139 |
|
140 result_type operator()() |
|
141 { |
|
142 return static_cast<IntType>(_rng() * _range) + _min; |
|
143 } |
|
144 |
|
145 private: |
|
146 typedef typename base_type::result_type base_result; |
|
147 uniform_01<base_type> _rng; |
|
148 IntType _min, _max; |
|
149 base_result _range; |
|
150 }; |
|
151 |
|
152 |
|
153 } // namespace detail |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 template<class IntType = int> |
|
159 class uniform_smallint |
|
160 { |
|
161 public: |
|
162 typedef IntType input_type; |
|
163 typedef IntType result_type; |
|
164 |
|
165 explicit uniform_smallint(IntType min = 0, IntType max = 9) |
|
166 : _min(min), _max(max) |
|
167 { |
|
168 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS |
|
169 // MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope |
|
170 BOOST_STATIC_ASSERT(std::numeric_limits<IntType>::is_integer); |
|
171 #endif |
|
172 } |
|
173 |
|
174 result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _min; } |
|
175 result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _max; } |
|
176 void reset() { } |
|
177 |
|
178 template<class Engine> |
|
179 result_type operator()(Engine& eng) |
|
180 { |
|
181 typedef typename Engine::result_type base_result; |
|
182 base_result _range = static_cast<base_result>(_max-_min)+1; |
|
183 base_result _factor = 1; |
|
184 |
|
185 // LCGs get bad when only taking the low bits. |
|
186 // (probably put this logic into a partial template specialization) |
|
187 // Check how many low bits we can ignore before we get too much |
|
188 // quantization error. |
|
189 base_result r_base = (eng.max)() - (eng.min)(); |
|
190 if(r_base == (std::numeric_limits<base_result>::max)()) { |
|
191 _factor = 2; |
|
192 r_base /= 2; |
|
193 } |
|
194 r_base += 1; |
|
195 if(r_base % _range == 0) { |
|
196 // No quantization effects, good |
|
197 _factor = r_base / _range; |
|
198 } else { |
|
199 // carefully avoid overflow; pessimizing heree |
|
200 for( ; r_base/_range/32 >= _range; _factor *= 2) |
|
201 r_base /= 2; |
|
202 } |
|
203 |
|
204 return ((eng() - (eng.min)()) / _factor) % _range + _min; |
|
205 } |
|
206 |
|
207 #if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) |
|
208 template<class CharT, class Traits> |
|
209 friend std::basic_ostream<CharT,Traits>& |
|
210 operator<<(std::basic_ostream<CharT,Traits>& os, const uniform_smallint& ud) |
|
211 { |
|
212 os << ud._min << " " << ud._max; |
|
213 return os; |
|
214 } |
|
215 |
|
216 template<class CharT, class Traits> |
|
217 friend std::basic_istream<CharT,Traits>& |
|
218 operator>>(std::basic_istream<CharT,Traits>& is, uniform_smallint& ud) |
|
219 { |
|
220 # if BOOST_WORKAROUND(_MSC_FULL_VER, BOOST_TESTED_AT(13102292)) && BOOST_MSVC > 1300 |
|
221 return detail::extract_uniform_int(is, ud, ud._impl); |
|
222 # else |
|
223 is >> std::ws >> ud._min >> std::ws >> ud._max; |
|
224 return is; |
|
225 # endif |
|
226 } |
|
227 #endif |
|
228 |
|
229 private: |
|
230 result_type _min; |
|
231 result_type _max; |
|
232 }; |
|
233 |
|
234 } // namespace boost |
|
235 |
|
236 #endif // BOOST_RANDOM_UNIFORM_SMALLINT_HPP |