source: NonGTP/Boost/boost/random/uniform_smallint.hpp @ 857

Revision 857, 6.8 KB checked in by igarcia, 18 years ago (diff)
Line 
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
32namespace boost {
33
34// uniform integer distribution on a small range [min, max]
35
36namespace detail {
37
38template <class InputStream, class UniformInt, class Impl>
39InputStream& 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
47template<class UniformRandomNumberGenerator, class IntType>
48struct uniform_smallint_integer
49{
50public:
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
70private:
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
78template<class UniformRandomNumberGenerator, class IntType>
79void uniform_smallint_integer<UniformRandomNumberGenerator, IntType>::
80set(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
109template<class UniformRandomNumberGenerator, class IntType>
110class uniform_smallint_float
111{
112public:
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
145private:
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
158template<class IntType = int>
159class uniform_smallint
160{
161public:
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
229private:
230  result_type _min;
231  result_type _max;
232};
233
234} // namespace boost
235
236#endif // BOOST_RANDOM_UNIFORM_SMALLINT_HPP
Note: See TracBrowser for help on using the repository browser.