/////////////////////////////////////////////////////////////// // 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 #include #include #include #include namespace boost { namespace multiprecision { namespace detail { template struct make_unsigned_impl { using type = typename boost::multiprecision::detail::make_unsigned::type; }; template struct make_unsigned_impl { using type = T; }; template struct make_unsigned_mp { using type = typename make_unsigned_impl::value>::type; }; template T generate_uniform_int (Engine& eng, T min_value, T max_value) { using range_type = typename boost::multiprecision::detail::make_unsigned_mp::type; using base_result = typename Engine::result_type; using base_unsigned = typename boost::multiprecision::detail::make_unsigned_mp::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::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(static_cast(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::is_bounded && ((std::numeric_limits::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::is_specialized && std::numeric_limits::is_specialized && (std::numeric_limits::digits >= std::numeric_limits::digits), range_type, base_unsigned>::type; mixed_range_type bucket_size; if(brange == (std::numeric_limits::max)()) { bucket_size = static_cast(brange) / (static_cast(range)+1); if(static_cast(brange) % (static_cast(range)+1) == static_cast(range)) { ++bucket_size; } } else { bucket_size = static_cast(brange + 1) / (static_cast(range)+1); } for(;;) { mixed_range_type result = eng() - bmin; result /= bucket_size; if(result <= static_cast(range)) { return result + min_value; } } } } } // Namespace detail template 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 Integer operator() (Engine& eng) const { return detail::generate_uniform_int(eng, min_, max_); } template 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