123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- ///////////////////////////////////////////////////////////////
- // Copyright Jens Maurer 2000-2021
- // Copyright Steven Watanabe 2011-2021
- // Copyright John Maddock 2015-2021
- // Copyright Matt Borland 2021
- // Distributed under the Boost Software License, Version 1.0.
- // (See accompanying file LICENSE_1_0.txt or copy at
- // https://www.boost.org/LICENSE_1_0.txt
- //
- // This is a C++11 compliant port of Boost.Random's implementation
- // of uniform_int_distribution. See their comments for detailed
- // descriptions
- #ifndef BOOST_MP_UNIFORM_INT_DISTRIBUTION_HPP
- #define BOOST_MP_UNIFORM_INT_DISTRIBUTION_HPP
- #include <limits>
- #include <type_traits>
- #include <boost/multiprecision/detail/standalone_config.hpp>
- #include <boost/multiprecision/detail/assert.hpp>
- #include <boost/multiprecision/traits/std_integer_traits.hpp>
- namespace boost { namespace multiprecision {
-
- namespace detail {
- template <typename T, bool intrinsic>
- struct make_unsigned_impl
- {
- using type = typename boost::multiprecision::detail::make_unsigned<T>::type;
- };
- template <typename T>
- struct make_unsigned_impl<T, false>
- {
- using type = T;
- };
- template <typename T>
- struct make_unsigned_mp
- {
- using type = typename make_unsigned_impl<T, boost::multiprecision::detail::is_integral<T>::value>::type;
- };
- template <typename Engine, typename T>
- T generate_uniform_int (Engine& eng, T min_value, T max_value)
- {
- using range_type = typename boost::multiprecision::detail::make_unsigned_mp<T>::type;
- using base_result = typename Engine::result_type;
- using base_unsigned = typename boost::multiprecision::detail::make_unsigned_mp<base_result>::type;
- const range_type range = max_value - min_value;
- const base_result bmin = (eng.min)();
- const base_unsigned brange = (eng.max)() - (eng.min)();
- if(range == 0)
- {
- return min_value;
- }
- else if (brange < range)
- {
- for(;;)
- {
- range_type limit;
- if(range == (std::numeric_limits<range_type>::max)())
- {
- limit = range / (range_type(brange) + 1);
- if(range % (range_type(brange) + 1) == range_type(brange))
- {
- ++limit;
- }
- }
- else
- {
- limit = (range + 1) / (range_type(brange) + 1);
- }
- range_type result = 0;
- range_type mult = 1;
- while (mult <= limit)
- {
- result += static_cast<range_type>(static_cast<range_type>(eng() - bmin) * mult);
- if(mult * range_type(brange) == range - mult + 1)
- {
- return(result);
- }
- mult *= range_type(brange)+range_type(1);
- }
- range_type result_increment = generate_uniform_int(eng, range_type(0), range_type(range/mult));
- if(std::numeric_limits<range_type>::is_bounded && ((std::numeric_limits<range_type>::max)() / mult < result_increment))
- {
- continue;
- }
- result_increment *= mult;
- result += result_increment;
- if(result < result_increment)
- {
- continue;
- }
- if(result > range)
- {
- continue;
- }
- return result + min_value;
- }
- }
- else
- {
- using mixed_range_type =
- typename std::conditional<std::numeric_limits<range_type>::is_specialized && std::numeric_limits<base_unsigned>::is_specialized &&
- (std::numeric_limits<range_type>::digits >= std::numeric_limits<base_unsigned>::digits),
- range_type, base_unsigned>::type;
- mixed_range_type bucket_size;
- if(brange == (std::numeric_limits<base_unsigned>::max)())
- {
- bucket_size = static_cast<mixed_range_type>(brange) / (static_cast<mixed_range_type>(range)+1);
- if(static_cast<mixed_range_type>(brange) % (static_cast<mixed_range_type>(range)+1) == static_cast<mixed_range_type>(range))
- {
- ++bucket_size;
- }
- }
- else
- {
- bucket_size = static_cast<mixed_range_type>(brange + 1) / (static_cast<mixed_range_type>(range)+1);
- }
- for(;;)
- {
- mixed_range_type result = eng() - bmin;
- result /= bucket_size;
- if(result <= static_cast<mixed_range_type>(range))
- {
- return result + min_value;
- }
- }
- }
- }
- } // Namespace detail
- template <typename Integer = int>
- class uniform_int_distribution
- {
- private:
- Integer min_;
- Integer max_;
- public:
- class param_type
- {
- private:
- Integer min_;
- Integer max_;
-
- public:
- explicit param_type(Integer min_val, Integer max_val) : min_ {min_val}, max_ {max_val}
- {
- BOOST_MP_ASSERT(min_ <= max_);
- }
- Integer a() const { return min_; }
- Integer b() const { return max_; }
- };
- explicit uniform_int_distribution(Integer min_arg, Integer max_arg) : min_ {min_arg}, max_ {max_arg}
- {
- BOOST_MP_ASSERT(min_ <= max_);
- }
- explicit uniform_int_distribution(const param_type& param_arg) : min_ {param_arg.a()}, max_ {param_arg.b()} {}
- Integer min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return min_; }
- Integer max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return max_; }
-
- Integer a() const { return min_; }
- Integer b() const { return max_; }
- param_type param() const { return param_type(min_, max_); }
- void param(const param_type& param_arg)
- {
- min_ = param_arg.a();
- max_ = param_arg.b();
- }
- template <typename Engine>
- Integer operator() (Engine& eng) const
- {
- return detail::generate_uniform_int(eng, min_, max_);
- }
- template <typename Engine>
- Integer operator() (Engine& eng, const param_type& param_arg) const
- {
- return detail::generate_uniform_int(eng, param_arg.a(), param_arg.b());
- }
- };
- }} // Namespaces
- #endif // BOOST_MP_UNIFORM_INT_DISTRIBUTION_HPP
|