annotate DEPENDENCIES/generic/include/boost/random/uniform_int_distribution.hpp @ 125:34e428693f5d vext

Vext -> Repoint
author Chris Cannam
date Thu, 14 Jun 2018 11:15:39 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 /* boost random/uniform_int_distribution.hpp header file
Chris@16 2 *
Chris@16 3 * Copyright Jens Maurer 2000-2001
Chris@16 4 * Copyright Steven Watanabe 2011
Chris@16 5 * Distributed under the Boost Software License, Version 1.0. (See
Chris@16 6 * accompanying file LICENSE_1_0.txt or copy at
Chris@16 7 * http://www.boost.org/LICENSE_1_0.txt)
Chris@16 8 *
Chris@16 9 * See http://www.boost.org for most recent version including documentation.
Chris@16 10 *
Chris@101 11 * $Id$
Chris@16 12 *
Chris@16 13 * Revision history
Chris@16 14 * 2001-04-08 added min<max assertion (N. Becker)
Chris@16 15 * 2001-02-18 moved to individual header files
Chris@16 16 */
Chris@16 17
Chris@16 18 #ifndef BOOST_RANDOM_UNIFORM_INT_DISTRIBUTION_HPP
Chris@16 19 #define BOOST_RANDOM_UNIFORM_INT_DISTRIBUTION_HPP
Chris@16 20
Chris@16 21 #include <iosfwd>
Chris@16 22 #include <ios>
Chris@16 23 #include <istream>
Chris@16 24 #include <boost/config.hpp>
Chris@16 25 #include <boost/limits.hpp>
Chris@16 26 #include <boost/assert.hpp>
Chris@16 27 #include <boost/random/detail/config.hpp>
Chris@16 28 #include <boost/random/detail/operators.hpp>
Chris@16 29 #include <boost/random/detail/uniform_int_float.hpp>
Chris@16 30 #include <boost/random/detail/signed_unsigned_tools.hpp>
Chris@16 31 #include <boost/type_traits/make_unsigned.hpp>
Chris@16 32 #include <boost/type_traits/is_integral.hpp>
Chris@101 33 #include <boost/mpl/bool.hpp>
Chris@16 34
Chris@16 35 namespace boost {
Chris@16 36 namespace random {
Chris@16 37 namespace detail {
Chris@16 38
Chris@16 39
Chris@16 40 #ifdef BOOST_MSVC
Chris@16 41 #pragma warning(push)
Chris@16 42 // disable division by zero warning, since we can't
Chris@16 43 // actually divide by zero.
Chris@16 44 #pragma warning(disable:4723)
Chris@16 45 #endif
Chris@16 46
Chris@16 47 template<class Engine, class T>
Chris@16 48 T generate_uniform_int(
Chris@16 49 Engine& eng, T min_value, T max_value,
Chris@16 50 boost::mpl::true_ /** is_integral<Engine::result_type> */)
Chris@16 51 {
Chris@16 52 typedef T result_type;
Chris@16 53 typedef typename make_unsigned<T>::type range_type;
Chris@16 54 typedef typename Engine::result_type base_result;
Chris@16 55 // ranges are always unsigned
Chris@16 56 typedef typename make_unsigned<base_result>::type base_unsigned;
Chris@16 57 const range_type range = random::detail::subtract<result_type>()(max_value, min_value);
Chris@16 58 const base_result bmin = (eng.min)();
Chris@16 59 const base_unsigned brange =
Chris@16 60 random::detail::subtract<base_result>()((eng.max)(), (eng.min)());
Chris@16 61
Chris@16 62 if(range == 0) {
Chris@16 63 return min_value;
Chris@16 64 } else if(brange == range) {
Chris@16 65 // this will probably never happen in real life
Chris@16 66 // basically nothing to do; just take care we don't overflow / underflow
Chris@16 67 base_unsigned v = random::detail::subtract<base_result>()(eng(), bmin);
Chris@16 68 return random::detail::add<base_unsigned, result_type>()(v, min_value);
Chris@16 69 } else if(brange < range) {
Chris@16 70 // use rejection method to handle things like 0..3 --> 0..4
Chris@16 71 for(;;) {
Chris@16 72 // concatenate several invocations of the base RNG
Chris@16 73 // take extra care to avoid overflows
Chris@16 74
Chris@16 75 // limit == floor((range+1)/(brange+1))
Chris@16 76 // Therefore limit*(brange+1) <= range+1
Chris@16 77 range_type limit;
Chris@16 78 if(range == (std::numeric_limits<range_type>::max)()) {
Chris@16 79 limit = range/(range_type(brange)+1);
Chris@16 80 if(range % (range_type(brange)+1) == range_type(brange))
Chris@16 81 ++limit;
Chris@16 82 } else {
Chris@16 83 limit = (range+1)/(range_type(brange)+1);
Chris@16 84 }
Chris@16 85
Chris@16 86 // We consider "result" as expressed to base (brange+1):
Chris@16 87 // For every power of (brange+1), we determine a random factor
Chris@16 88 range_type result = range_type(0);
Chris@16 89 range_type mult = range_type(1);
Chris@16 90
Chris@16 91 // loop invariants:
Chris@16 92 // result < mult
Chris@16 93 // mult <= range
Chris@16 94 while(mult <= limit) {
Chris@16 95 // Postcondition: result <= range, thus no overflow
Chris@16 96 //
Chris@16 97 // limit*(brange+1)<=range+1 def. of limit (1)
Chris@16 98 // eng()-bmin<=brange eng() post. (2)
Chris@16 99 // and mult<=limit. loop condition (3)
Chris@16 100 // Therefore mult*(eng()-bmin+1)<=range+1 by (1),(2),(3) (4)
Chris@16 101 // Therefore mult*(eng()-bmin)+mult<=range+1 rearranging (4) (5)
Chris@16 102 // result<mult loop invariant (6)
Chris@16 103 // Therefore result+mult*(eng()-bmin)<range+1 by (5), (6) (7)
Chris@16 104 //
Chris@16 105 // Postcondition: result < mult*(brange+1)
Chris@16 106 //
Chris@16 107 // result<mult loop invariant (1)
Chris@16 108 // eng()-bmin<=brange eng() post. (2)
Chris@16 109 // Therefore result+mult*(eng()-bmin) <
Chris@16 110 // mult+mult*(eng()-bmin) by (1) (3)
Chris@16 111 // Therefore result+(eng()-bmin)*mult <
Chris@16 112 // mult+mult*brange by (2), (3) (4)
Chris@16 113 // Therefore result+(eng()-bmin)*mult <
Chris@16 114 // mult*(brange+1) by (4)
Chris@16 115 result += static_cast<range_type>(random::detail::subtract<base_result>()(eng(), bmin) * mult);
Chris@16 116
Chris@16 117 // equivalent to (mult * (brange+1)) == range+1, but avoids overflow.
Chris@16 118 if(mult * range_type(brange) == range - mult + 1) {
Chris@16 119 // The destination range is an integer power of
Chris@16 120 // the generator's range.
Chris@16 121 return(result);
Chris@16 122 }
Chris@16 123
Chris@16 124 // Postcondition: mult <= range
Chris@16 125 //
Chris@16 126 // limit*(brange+1)<=range+1 def. of limit (1)
Chris@16 127 // mult<=limit loop condition (2)
Chris@16 128 // Therefore mult*(brange+1)<=range+1 by (1), (2) (3)
Chris@16 129 // mult*(brange+1)!=range+1 preceding if (4)
Chris@16 130 // Therefore mult*(brange+1)<range+1 by (3), (4) (5)
Chris@16 131 //
Chris@16 132 // Postcondition: result < mult
Chris@16 133 //
Chris@16 134 // See the second postcondition on the change to result.
Chris@16 135 mult *= range_type(brange)+range_type(1);
Chris@16 136 }
Chris@16 137 // loop postcondition: range/mult < brange+1
Chris@16 138 //
Chris@16 139 // mult > limit loop condition (1)
Chris@16 140 // Suppose range/mult >= brange+1 Assumption (2)
Chris@16 141 // range >= mult*(brange+1) by (2) (3)
Chris@16 142 // range+1 > mult*(brange+1) by (3) (4)
Chris@16 143 // range+1 > (limit+1)*(brange+1) by (1), (4) (5)
Chris@16 144 // (range+1)/(brange+1) > limit+1 by (5) (6)
Chris@16 145 // limit < floor((range+1)/(brange+1)) by (6) (7)
Chris@16 146 // limit==floor((range+1)/(brange+1)) def. of limit (8)
Chris@16 147 // not (2) reductio (9)
Chris@16 148 //
Chris@16 149 // loop postcondition: (range/mult)*mult+(mult-1) >= range
Chris@16 150 //
Chris@16 151 // (range/mult)*mult + range%mult == range identity (1)
Chris@16 152 // range%mult < mult def. of % (2)
Chris@16 153 // (range/mult)*mult+mult > range by (1), (2) (3)
Chris@16 154 // (range/mult)*mult+(mult-1) >= range by (3) (4)
Chris@16 155 //
Chris@16 156 // Note that the maximum value of result at this point is (mult-1),
Chris@16 157 // so after this final step, we generate numbers that can be
Chris@16 158 // at least as large as range. We have to really careful to avoid
Chris@16 159 // overflow in this final addition and in the rejection. Anything
Chris@16 160 // that overflows is larger than range and can thus be rejected.
Chris@16 161
Chris@16 162 // range/mult < brange+1 -> no endless loop
Chris@16 163 range_type result_increment =
Chris@16 164 generate_uniform_int(
Chris@16 165 eng,
Chris@16 166 static_cast<range_type>(0),
Chris@16 167 static_cast<range_type>(range/mult),
Chris@16 168 boost::mpl::true_());
Chris@16 169 if((std::numeric_limits<range_type>::max)() / mult < result_increment) {
Chris@16 170 // The multiplcation would overflow. Reject immediately.
Chris@16 171 continue;
Chris@16 172 }
Chris@16 173 result_increment *= mult;
Chris@16 174 // unsigned integers are guaranteed to wrap on overflow.
Chris@16 175 result += result_increment;
Chris@16 176 if(result < result_increment) {
Chris@16 177 // The addition overflowed. Reject.
Chris@16 178 continue;
Chris@16 179 }
Chris@16 180 if(result > range) {
Chris@16 181 // Too big. Reject.
Chris@16 182 continue;
Chris@16 183 }
Chris@16 184 return random::detail::add<range_type, result_type>()(result, min_value);
Chris@16 185 }
Chris@16 186 } else { // brange > range
Chris@16 187 base_unsigned bucket_size;
Chris@16 188 // it's safe to add 1 to range, as long as we cast it first,
Chris@16 189 // because we know that it is less than brange. However,
Chris@16 190 // we do need to be careful not to cause overflow by adding 1
Chris@16 191 // to brange.
Chris@16 192 if(brange == (std::numeric_limits<base_unsigned>::max)()) {
Chris@16 193 bucket_size = brange / (static_cast<base_unsigned>(range)+1);
Chris@16 194 if(brange % (static_cast<base_unsigned>(range)+1) == static_cast<base_unsigned>(range)) {
Chris@16 195 ++bucket_size;
Chris@16 196 }
Chris@16 197 } else {
Chris@16 198 bucket_size = (brange+1) / (static_cast<base_unsigned>(range)+1);
Chris@16 199 }
Chris@16 200 for(;;) {
Chris@16 201 base_unsigned result =
Chris@16 202 random::detail::subtract<base_result>()(eng(), bmin);
Chris@16 203 result /= bucket_size;
Chris@16 204 // result and range are non-negative, and result is possibly larger
Chris@16 205 // than range, so the cast is safe
Chris@16 206 if(result <= static_cast<base_unsigned>(range))
Chris@16 207 return random::detail::add<base_unsigned, result_type>()(result, min_value);
Chris@16 208 }
Chris@16 209 }
Chris@16 210 }
Chris@16 211
Chris@16 212 #ifdef BOOST_MSVC
Chris@16 213 #pragma warning(pop)
Chris@16 214 #endif
Chris@16 215
Chris@16 216 template<class Engine, class T>
Chris@16 217 inline T generate_uniform_int(
Chris@16 218 Engine& eng, T min_value, T max_value,
Chris@16 219 boost::mpl::false_ /** is_integral<Engine::result_type> */)
Chris@16 220 {
Chris@16 221 uniform_int_float<Engine> wrapper(eng);
Chris@16 222 return generate_uniform_int(wrapper, min_value, max_value, boost::mpl::true_());
Chris@16 223 }
Chris@16 224
Chris@16 225 template<class Engine, class T>
Chris@16 226 inline T generate_uniform_int(Engine& eng, T min_value, T max_value)
Chris@16 227 {
Chris@16 228 typedef typename Engine::result_type base_result;
Chris@16 229 return generate_uniform_int(eng, min_value, max_value,
Chris@16 230 boost::is_integral<base_result>());
Chris@16 231 }
Chris@16 232
Chris@16 233 }
Chris@16 234
Chris@16 235 /**
Chris@16 236 * The class template uniform_int_distribution models a \random_distribution.
Chris@16 237 * On each invocation, it returns a random integer value uniformly
Chris@16 238 * distributed in the set of integers {min, min+1, min+2, ..., max}.
Chris@16 239 *
Chris@16 240 * The template parameter IntType shall denote an integer-like value type.
Chris@16 241 */
Chris@16 242 template<class IntType = int>
Chris@16 243 class uniform_int_distribution
Chris@16 244 {
Chris@16 245 public:
Chris@16 246 typedef IntType input_type;
Chris@16 247 typedef IntType result_type;
Chris@16 248
Chris@16 249 class param_type
Chris@16 250 {
Chris@16 251 public:
Chris@16 252
Chris@16 253 typedef uniform_int_distribution distribution_type;
Chris@16 254
Chris@16 255 /**
Chris@16 256 * Constructs the parameters of a uniform_int_distribution.
Chris@16 257 *
Chris@16 258 * Requires min <= max
Chris@16 259 */
Chris@16 260 explicit param_type(
Chris@16 261 IntType min_arg = 0,
Chris@16 262 IntType max_arg = (std::numeric_limits<IntType>::max)())
Chris@16 263 : _min(min_arg), _max(max_arg)
Chris@16 264 {
Chris@16 265 BOOST_ASSERT(_min <= _max);
Chris@16 266 }
Chris@16 267
Chris@16 268 /** Returns the minimum value of the distribution. */
Chris@16 269 IntType a() const { return _min; }
Chris@16 270 /** Returns the maximum value of the distribution. */
Chris@16 271 IntType b() const { return _max; }
Chris@16 272
Chris@16 273 /** Writes the parameters to a @c std::ostream. */
Chris@16 274 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm)
Chris@16 275 {
Chris@16 276 os << parm._min << " " << parm._max;
Chris@16 277 return os;
Chris@16 278 }
Chris@16 279
Chris@16 280 /** Reads the parameters from a @c std::istream. */
Chris@16 281 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm)
Chris@16 282 {
Chris@16 283 IntType min_in, max_in;
Chris@16 284 if(is >> min_in >> std::ws >> max_in) {
Chris@16 285 if(min_in <= max_in) {
Chris@16 286 parm._min = min_in;
Chris@16 287 parm._max = max_in;
Chris@16 288 } else {
Chris@16 289 is.setstate(std::ios_base::failbit);
Chris@16 290 }
Chris@16 291 }
Chris@16 292 return is;
Chris@16 293 }
Chris@16 294
Chris@16 295 /** Returns true if the two sets of parameters are equal. */
Chris@16 296 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs)
Chris@16 297 { return lhs._min == rhs._min && lhs._max == rhs._max; }
Chris@16 298
Chris@16 299 /** Returns true if the two sets of parameters are different. */
Chris@16 300 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type)
Chris@16 301
Chris@16 302 private:
Chris@16 303
Chris@16 304 IntType _min;
Chris@16 305 IntType _max;
Chris@16 306 };
Chris@16 307
Chris@16 308 /**
Chris@16 309 * Constructs a uniform_int_distribution. @c min and @c max are
Chris@16 310 * the parameters of the distribution.
Chris@16 311 *
Chris@16 312 * Requires: min <= max
Chris@16 313 */
Chris@16 314 explicit uniform_int_distribution(
Chris@16 315 IntType min_arg = 0,
Chris@16 316 IntType max_arg = (std::numeric_limits<IntType>::max)())
Chris@16 317 : _min(min_arg), _max(max_arg)
Chris@16 318 {
Chris@16 319 BOOST_ASSERT(min_arg <= max_arg);
Chris@16 320 }
Chris@16 321 /** Constructs a uniform_int_distribution from its parameters. */
Chris@16 322 explicit uniform_int_distribution(const param_type& parm)
Chris@16 323 : _min(parm.a()), _max(parm.b()) {}
Chris@16 324
Chris@16 325 /** Returns the minimum value of the distribution */
Chris@16 326 IntType min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _min; }
Chris@16 327 /** Returns the maximum value of the distribution */
Chris@16 328 IntType max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _max; }
Chris@16 329
Chris@16 330 /** Returns the minimum value of the distribution */
Chris@16 331 IntType a() const { return _min; }
Chris@16 332 /** Returns the maximum value of the distribution */
Chris@16 333 IntType b() const { return _max; }
Chris@16 334
Chris@16 335 /** Returns the parameters of the distribution. */
Chris@16 336 param_type param() const { return param_type(_min, _max); }
Chris@16 337 /** Sets the parameters of the distribution. */
Chris@16 338 void param(const param_type& parm)
Chris@16 339 {
Chris@16 340 _min = parm.a();
Chris@16 341 _max = parm.b();
Chris@16 342 }
Chris@16 343
Chris@16 344 /**
Chris@16 345 * Effects: Subsequent uses of the distribution do not depend
Chris@16 346 * on values produced by any engine prior to invoking reset.
Chris@16 347 */
Chris@16 348 void reset() { }
Chris@16 349
Chris@16 350 /** Returns an integer uniformly distributed in the range [min, max]. */
Chris@16 351 template<class Engine>
Chris@16 352 result_type operator()(Engine& eng) const
Chris@16 353 { return detail::generate_uniform_int(eng, _min, _max); }
Chris@16 354
Chris@16 355 /**
Chris@16 356 * Returns an integer uniformly distributed in the range
Chris@16 357 * [param.a(), param.b()].
Chris@16 358 */
Chris@16 359 template<class Engine>
Chris@16 360 result_type operator()(Engine& eng, const param_type& parm) const
Chris@16 361 { return detail::generate_uniform_int(eng, parm.a(), parm.b()); }
Chris@16 362
Chris@16 363 /** Writes the distribution to a @c std::ostream. */
Chris@16 364 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, uniform_int_distribution, ud)
Chris@16 365 {
Chris@16 366 os << ud.param();
Chris@16 367 return os;
Chris@16 368 }
Chris@16 369
Chris@16 370 /** Reads the distribution from a @c std::istream. */
Chris@16 371 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, uniform_int_distribution, ud)
Chris@16 372 {
Chris@16 373 param_type parm;
Chris@16 374 if(is >> parm) {
Chris@16 375 ud.param(parm);
Chris@16 376 }
Chris@16 377 return is;
Chris@16 378 }
Chris@16 379
Chris@16 380 /**
Chris@16 381 * Returns true if the two distributions will produce identical sequences
Chris@16 382 * of values given equal generators.
Chris@16 383 */
Chris@16 384 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(uniform_int_distribution, lhs, rhs)
Chris@16 385 { return lhs._min == rhs._min && lhs._max == rhs._max; }
Chris@16 386
Chris@16 387 /**
Chris@16 388 * Returns true if the two distributions may produce different sequences
Chris@16 389 * of values given equal generators.
Chris@16 390 */
Chris@16 391 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(uniform_int_distribution)
Chris@16 392
Chris@16 393 private:
Chris@16 394 IntType _min;
Chris@16 395 IntType _max;
Chris@16 396 };
Chris@16 397
Chris@16 398 } // namespace random
Chris@16 399 } // namespace boost
Chris@16 400
Chris@16 401 #endif // BOOST_RANDOM_UNIFORM_INT_HPP