1 /* boost random/uniform_smallint.hpp header file
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)
8 * See http://www.boost.org for most recent version including documentation.
10 * $Id: uniform_smallint.hpp,v 1.29 2004/07/27 03:43:32 dgregor Exp $
13 * 2001-04-08 added min<max assertion (N. Becker)
14 * 2001-02-18 moved to individual header files
17 #ifndef BOOST_RANDOM_UNIFORM_SMALLINT_HPP
18 #define BOOST_RANDOM_UNIFORM_SMALLINT_HPP
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>
34 // uniform integer distribution on a small range [min, max]
38 template <class InputStream, class UniformInt, class Impl>
39 InputStream& extract_uniform_int(InputStream& is, UniformInt& ud, Impl& impl)
41 typename UniformInt::result_type min, max;
42 is >> std::ws >> min >> std::ws >> max;
47 template<class UniformRandomNumberGenerator, class IntType>
48 struct uniform_smallint_integer
51 typedef UniformRandomNumberGenerator base_type;
52 typedef IntType result_type;
54 uniform_smallint_integer(base_type & rng, IntType min, IntType max)
58 void set(result_type min, result_type max);
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; }
64 result_type operator()()
66 // we must not use the low bits here, because LCGs get very bad then
67 return (((*_rng)() - (_rng->min)()) / _factor) % _range + _min;
71 typedef typename base_type::result_type base_result;
78 template<class UniformRandomNumberGenerator, class IntType>
79 void uniform_smallint_integer<UniformRandomNumberGenerator, IntType>::
80 set(result_type min, result_type max)
86 _range = static_cast<base_result>(_max-_min)+1;
87 base_result _factor = 1;
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)()) {
99 if(r_base % _range == 0) {
100 // No quantization effects, good
101 _factor = r_base / _range;
103 // carefully avoid overflow; pessimizing heree
104 for( ; r_base/_range/32 >= _range; _factor *= 2)
109 template<class UniformRandomNumberGenerator, class IntType>
110 class uniform_smallint_float
113 typedef UniformRandomNumberGenerator base_type;
114 typedef IntType result_type;
116 uniform_smallint_float(base_type & rng, IntType min, IntType max)
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);
129 void set(result_type min, result_type max)
133 _range = static_cast<base_result>(_max-_min)+1;
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(); }
140 result_type operator()()
142 return static_cast<IntType>(_rng() * _range) + _min;
146 typedef typename base_type::result_type base_result;
147 uniform_01<base_type> _rng;
153 } // namespace detail
158 template<class IntType = int>
159 class uniform_smallint
162 typedef IntType input_type;
163 typedef IntType result_type;
165 explicit uniform_smallint(IntType min = 0, IntType max = 9)
166 : _min(min), _max(max)
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);
174 result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _min; }
175 result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _max; }
178 template<class Engine>
179 result_type operator()(Engine& eng)
181 typedef typename Engine::result_type base_result;
182 base_result _range = static_cast<base_result>(_max-_min)+1;
183 base_result _factor = 1;
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)()) {
195 if(r_base % _range == 0) {
196 // No quantization effects, good
197 _factor = r_base / _range;
199 // carefully avoid overflow; pessimizing heree
200 for( ; r_base/_range/32 >= _range; _factor *= 2)
204 return ((eng() - (eng.min)()) / _factor) % _range + _min;
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)
212 os << ud._min << " " << ud._max;
216 template<class CharT, class Traits>
217 friend std::basic_istream<CharT,Traits>&
218 operator>>(std::basic_istream<CharT,Traits>& is, uniform_smallint& ud)
220 # if BOOST_WORKAROUND(_MSC_FULL_VER, BOOST_TESTED_AT(13102292)) && BOOST_MSVC > 1300
221 return detail::extract_uniform_int(is, ud, ud._impl);
223 is >> std::ws >> ud._min >> std::ws >> ud._max;
236 #endif // BOOST_RANDOM_UNIFORM_SMALLINT_HPP