File indexing completed on 2025-01-18 09:51:13
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #ifndef BOOST_RANDOM_UNIFORM_INT_DISTRIBUTION_HPP
0019 #define BOOST_RANDOM_UNIFORM_INT_DISTRIBUTION_HPP
0020
0021 #include <iosfwd>
0022 #include <ios>
0023 #include <istream>
0024 #include <boost/config.hpp>
0025 #include <boost/limits.hpp>
0026 #include <boost/assert.hpp>
0027 #include <boost/random/detail/config.hpp>
0028 #include <boost/random/detail/operators.hpp>
0029 #include <boost/random/detail/uniform_int_float.hpp>
0030 #include <boost/random/detail/signed_unsigned_tools.hpp>
0031 #include <boost/random/traits.hpp>
0032 #include <boost/type_traits/integral_constant.hpp>
0033 #ifdef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
0034 #include <boost/type_traits/conditional.hpp>
0035 #endif
0036
0037 namespace boost {
0038 namespace random {
0039 namespace detail {
0040
0041
0042 #ifdef BOOST_MSVC
0043 #pragma warning(push)
0044
0045
0046 #pragma warning(disable:4723)
0047 #endif
0048
0049 template<class Engine, class T>
0050 T generate_uniform_int(
0051 Engine& eng, T min_value, T max_value,
0052 boost::true_type )
0053 {
0054 typedef T result_type;
0055 typedef typename boost::random::traits::make_unsigned_or_unbounded<T>::type range_type;
0056 typedef typename Engine::result_type base_result;
0057
0058 typedef typename boost::random::traits::make_unsigned_or_unbounded<base_result>::type base_unsigned;
0059 const range_type range = random::detail::subtract<result_type>()(max_value, min_value);
0060 const base_result bmin = (eng.min)();
0061 const base_unsigned brange =
0062 random::detail::subtract<base_result>()((eng.max)(), (eng.min)());
0063
0064 if(range == 0) {
0065 return min_value;
0066 } else if(brange == range) {
0067
0068
0069 base_unsigned v = random::detail::subtract<base_result>()(eng(), bmin);
0070 return random::detail::add<base_unsigned, result_type>()(v, min_value);
0071 } else if(brange < range) {
0072
0073 for(;;) {
0074
0075
0076
0077
0078
0079 range_type limit;
0080 if(range == (std::numeric_limits<range_type>::max)()) {
0081 limit = range/(range_type(brange)+1);
0082 if(range % (range_type(brange)+1) == range_type(brange))
0083 ++limit;
0084 } else {
0085 limit = (range+1)/(range_type(brange)+1);
0086 }
0087
0088
0089
0090 range_type result = range_type(0);
0091 range_type mult = range_type(1);
0092
0093
0094
0095
0096 while(mult <= limit) {
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117 result += static_cast<range_type>(static_cast<range_type>(random::detail::subtract<base_result>()(eng(), bmin)) * mult);
0118
0119
0120 if(mult * range_type(brange) == range - mult + 1) {
0121
0122
0123 return(result);
0124 }
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137 mult *= range_type(brange)+range_type(1);
0138 }
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165 range_type result_increment =
0166 generate_uniform_int(
0167 eng,
0168 static_cast<range_type>(0),
0169 static_cast<range_type>(range/mult),
0170 boost::true_type());
0171 if(std::numeric_limits<range_type>::is_bounded && ((std::numeric_limits<range_type>::max)() / mult < result_increment)) {
0172
0173 continue;
0174 }
0175 result_increment *= mult;
0176
0177 result += result_increment;
0178 if(result < result_increment) {
0179
0180 continue;
0181 }
0182 if(result > range) {
0183
0184 continue;
0185 }
0186 return random::detail::add<range_type, result_type>()(result, min_value);
0187 }
0188 } else {
0189 #ifdef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
0190 typedef typename conditional<
0191 std::numeric_limits<range_type>::is_specialized && std::numeric_limits<base_unsigned>::is_specialized
0192 && (std::numeric_limits<range_type>::digits >= std::numeric_limits<base_unsigned>::digits),
0193 range_type, base_unsigned>::type mixed_range_type;
0194 #else
0195 typedef base_unsigned mixed_range_type;
0196 #endif
0197
0198 mixed_range_type bucket_size;
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210 if(brange == (std::numeric_limits<base_unsigned>::max)()) {
0211 bucket_size = static_cast<mixed_range_type>(brange) / (static_cast<mixed_range_type>(range)+1);
0212 if(static_cast<mixed_range_type>(brange) % (static_cast<mixed_range_type>(range)+1) == static_cast<mixed_range_type>(range)) {
0213 ++bucket_size;
0214 }
0215 } else {
0216 bucket_size = static_cast<mixed_range_type>(brange + 1) / (static_cast<mixed_range_type>(range)+1);
0217 }
0218 for(;;) {
0219 mixed_range_type result =
0220 random::detail::subtract<base_result>()(eng(), bmin);
0221 result /= bucket_size;
0222
0223
0224 if(result <= static_cast<mixed_range_type>(range))
0225 return random::detail::add<mixed_range_type, result_type>()(result, min_value);
0226 }
0227 }
0228 }
0229
0230 #ifdef BOOST_MSVC
0231 #pragma warning(pop)
0232 #endif
0233
0234 template<class Engine, class T>
0235 inline T generate_uniform_int(
0236 Engine& eng, T min_value, T max_value,
0237 boost::false_type )
0238 {
0239 uniform_int_float<Engine> wrapper(eng);
0240 return generate_uniform_int(wrapper, min_value, max_value, boost::true_type());
0241 }
0242
0243 template<class Engine, class T>
0244 inline T generate_uniform_int(Engine& eng, T min_value, T max_value)
0245 {
0246 typedef typename Engine::result_type base_result;
0247 return generate_uniform_int(eng, min_value, max_value,
0248 boost::random::traits::is_integral<base_result>());
0249 }
0250
0251 }
0252
0253
0254
0255
0256
0257
0258
0259
0260 template<class IntType = int>
0261 class uniform_int_distribution
0262 {
0263 public:
0264 typedef IntType input_type;
0265 typedef IntType result_type;
0266
0267 class param_type
0268 {
0269 public:
0270
0271 typedef uniform_int_distribution distribution_type;
0272
0273
0274
0275
0276
0277
0278 explicit param_type(
0279 IntType min_arg = 0,
0280 IntType max_arg = (std::numeric_limits<IntType>::max)())
0281 : _min(min_arg), _max(max_arg)
0282 {
0283 BOOST_ASSERT(_min <= _max);
0284 }
0285
0286
0287 IntType a() const { return _min; }
0288
0289 IntType b() const { return _max; }
0290
0291
0292 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm)
0293 {
0294 os << parm._min << " " << parm._max;
0295 return os;
0296 }
0297
0298
0299 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm)
0300 {
0301 IntType min_in, max_in;
0302 if(is >> min_in >> std::ws >> max_in) {
0303 if(min_in <= max_in) {
0304 parm._min = min_in;
0305 parm._max = max_in;
0306 } else {
0307 is.setstate(std::ios_base::failbit);
0308 }
0309 }
0310 return is;
0311 }
0312
0313
0314 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs)
0315 { return lhs._min == rhs._min && lhs._max == rhs._max; }
0316
0317
0318 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type)
0319
0320 private:
0321
0322 IntType _min;
0323 IntType _max;
0324 };
0325
0326
0327
0328
0329
0330
0331
0332 explicit uniform_int_distribution(
0333 IntType min_arg = 0,
0334 IntType max_arg = (std::numeric_limits<IntType>::max)())
0335 : _min(min_arg), _max(max_arg)
0336 {
0337 BOOST_ASSERT(min_arg <= max_arg);
0338 }
0339
0340 explicit uniform_int_distribution(const param_type& parm)
0341 : _min(parm.a()), _max(parm.b()) {}
0342
0343
0344 IntType min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _min; }
0345
0346 IntType max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _max; }
0347
0348
0349 IntType a() const { return _min; }
0350
0351 IntType b() const { return _max; }
0352
0353
0354 param_type param() const { return param_type(_min, _max); }
0355
0356 void param(const param_type& parm)
0357 {
0358 _min = parm.a();
0359 _max = parm.b();
0360 }
0361
0362
0363
0364
0365
0366 void reset() { }
0367
0368
0369 template<class Engine>
0370 result_type operator()(Engine& eng) const
0371 { return detail::generate_uniform_int(eng, _min, _max); }
0372
0373
0374
0375
0376
0377 template<class Engine>
0378 result_type operator()(Engine& eng, const param_type& parm) const
0379 { return detail::generate_uniform_int(eng, parm.a(), parm.b()); }
0380
0381
0382 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, uniform_int_distribution, ud)
0383 {
0384 os << ud.param();
0385 return os;
0386 }
0387
0388
0389 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, uniform_int_distribution, ud)
0390 {
0391 param_type parm;
0392 if(is >> parm) {
0393 ud.param(parm);
0394 }
0395 return is;
0396 }
0397
0398
0399
0400
0401
0402 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(uniform_int_distribution, lhs, rhs)
0403 { return lhs._min == rhs._min && lhs._max == rhs._max; }
0404
0405
0406
0407
0408
0409 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(uniform_int_distribution)
0410
0411 private:
0412 IntType _min;
0413 IntType _max;
0414 };
0415
0416 }
0417 }
0418
0419 #endif