diff --git a/sprout/random.hpp b/sprout/random.hpp index 7bb9a349..ff9bfb32 100644 --- a/sprout/random.hpp +++ b/sprout/random.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/sprout/random/detail/const_mod.hpp b/sprout/random/detail/const_mod.hpp index f1e5dcb9..2bcc2bb9 100644 --- a/sprout/random/detail/const_mod.hpp +++ b/sprout/random/detail/const_mod.hpp @@ -1,8 +1,8 @@ -#ifndef SPROUT_RANDOM_CONST_MOD_HPP -#define SPROUT_RANDOM_CONST_MOD_HPP +#ifndef SPROUT_RANDOM_DETAIL_CONST_MOD_HPP +#define SPROUT_RANDOM_DETAIL_CONST_MOD_HPP -#include #include +#include #include namespace sprout { @@ -128,5 +128,5 @@ namespace sprout { } // namespace random } // namespace sprout -#endif // #ifndef SPROUT_RANDOM_CONST_MOD_HPP +#endif // #ifndef SPROUT_RANDOM_DETAIL_CONST_MOD_HPP diff --git a/sprout/random/detail/generator_bits.hpp b/sprout/random/detail/generator_bits.hpp new file mode 100644 index 00000000..1c2a4058 --- /dev/null +++ b/sprout/random/detail/generator_bits.hpp @@ -0,0 +1,23 @@ +#ifndef SPROUT_RANDOM_DETAIL_GENERATOR_BITS_HPP +#define SPROUT_RANDOM_DETAIL_GENERATOR_BITS_HPP + +#include +#include +#include + +namespace sprout { + namespace random { + namespace detail { + template + struct generator_bits { + public: + static SPROUT_CONSTEXPR std::size_t value() { + return std::numeric_limits::digits; + } + }; + } // namespace detail + } // namespace random +} // namespace sprout + +#endif // #ifndef SPROUT_RANDOM_DETAIL_GENERATOR_BITS_HPP + diff --git a/sprout/random/detail/uniform_int_float.hpp b/sprout/random/detail/uniform_int_float.hpp new file mode 100644 index 00000000..dfb456eb --- /dev/null +++ b/sprout/random/detail/uniform_int_float.hpp @@ -0,0 +1,74 @@ +#ifndef SPROUT_RANDOM_DETAIL_UNIFORM_INT_FLOAT_HPP +#define SPROUT_RANDOM_DETAIL_UNIFORM_INT_FLOAT_HPP + +#include +#include +#include +#include +#include +#include +#include +#include HDR_ALGORITHM_SSCRISK_CEL_OR_SPROUT_DETAIL + +namespace sprout { + namespace random { + namespace detail { + template + class uniform_int_float { + public: + typedef URNG base_type; + typedef typename base_type::result_type base_result; + typedef typename sprout::detail::uint_t< + (std::numeric_limits::digits < std::numeric_limits::digits) + ? std::numeric_limits::digits + : std::numeric_limits::digits + >::fast result_type; + private: + base_type rng_; + public: + //uniform_int_float = default; // ??? + SPROUT_CONSTEXPR uniform_int_float() + : rng_() + {} + SPROUT_CONSTEXPR explicit uniform_int_float(base_type const& rng) + : rng_(rng) + {} + SPROUT_CONSTEXPR result_type min() const { + return 0; + } + SPROUT_CONSTEXPR result_type max() const { + return ( + result_type(2) << ( + NS_SSCRISK_CEL_OR_SPROUT_DETAIL::min( + std::numeric_limits::digits, + sprout::random::detail::generator_bits::value() + ) - 1 + ) + ) - 1 + ; + } + base_type& base() { + return rng_; + } + SPROUT_CONSTEXPR base_type const& base() const { + return rng_; + } + SPROUT_CONSTEXPR sprout::random::random_result generate( + sprout::random::random_result const& rnd + ) const + { + return sprout::random::random_result( + static_cast(rnd.result() * (static_cast(max()) + 1)), + uniform_int_float(rnd.engine()) + ); + } + SPROUT_CONSTEXPR sprout::random::random_result operator()() const { + return generate(rng_()); + } + }; + } // namespace detail + } // namespace random +} // namespace sprout + +#endif // #ifndef SPROUT_RANDOM_DETAIL_UNIFORM_INT_FLOAT_HPP + diff --git a/sprout/random/uniform_int_distribution.hpp b/sprout/random/uniform_int_distribution.hpp new file mode 100644 index 00000000..292bbe65 --- /dev/null +++ b/sprout/random/uniform_int_distribution.hpp @@ -0,0 +1,530 @@ +#ifndef SPROUT_RANDOM_UNIFORM_INT_DISTRIBUTION_HPP +#define SPROUT_RANDOM_UNIFORM_INT_DISTRIBUTION_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sprout { + namespace random { + namespace detail { + // + // generate_uniform_int_result + // + template + struct generate_uniform_int_result { + public: + T result; + Engine engine; + }; + + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int( + Engine const& eng, + T min_value, + T max_value, + std::true_type + ); + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_3_1( + sprout::random::random_result const& rnd, + T min_value, + RangeType range, + BaseResult bmin, + BaseUnsigned brange, + BaseUnsigned bucket_size + ); + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_3_1_1( + Engine const& eng, + T min_value, + RangeType range, + BaseResult bmin, + BaseUnsigned brange, + BaseUnsigned bucket_size, + BaseUnsigned result + ) + { + typedef T result_type; + return result <= static_cast(range) + ? sprout::random::detail::generate_uniform_int_result{ + sprout::random::detail::add()(result, min_value), + eng + } + : generate_uniform_int_true_3_1( + eng(), + min_value, + range, + bmin, + brange, + bucket_size + ) + ; + } + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_3_1( + sprout::random::random_result const& rnd, + T min_value, + RangeType range, + BaseResult bmin, + BaseUnsigned brange, + BaseUnsigned bucket_size + ) + { + return sprout::random::detail::generate_uniform_int_true_3_1_1( + rnd.engine(), + min_value, + range, + bmin, + brange, + bucket_size, + sprout::random::detail::subtract()(rnd.result(), bmin) / bucket_size + ); + } + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_3( + Engine const& eng, + T min_value, + RangeType range, + BaseResult bmin, + BaseUnsigned brange + ) + { + return sprout::random::detail::generate_uniform_int_true_3_1( + eng(), + min_value, + range, + bmin, + brange, + brange == std::numeric_limits::max() + ? brange / (static_cast(range) + 1) + ( + brange % (static_cast(range) + 1) == static_cast(range) ? 1 : 0 + ) + : (brange + 1) / (static_cast(range) + 1) + ); + } + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2( + Engine const& eng, + T min_value, + RangeType range, + BaseResult bmin, + BaseUnsigned brange + ); + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_4( + Engine const& eng, + T min_value, + RangeType range, + BaseResult bmin, + BaseUnsigned brange, + RangeType result, + RangeType result_increment + ) + { + typedef T result_type; + return result < result_increment || result > range + ? sprout::random::detail::generate_uniform_int_true_2(eng, min_value, range, bmin, brange) + : sprout::random::detail::generate_uniform_int_result{ + random::detail::add()(result, min_value), + eng + } + ; + } + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_3( + Engine const& eng, + T min_value, + RangeType range, + BaseResult bmin, + BaseUnsigned brange, + RangeType result, + RangeType mult, + RangeType result_increment + ) + { + return std::numeric_limits::max() / mult < result_increment + ? sprout::random::detail::generate_uniform_int_true_2(eng, min_value, range, bmin, brange) + : generate_uniform_int_true_2_4( + eng, + min_value, + range, + bmin, + brange, + result + (result_increment * mult), + result_increment * mult + ) + ; + } + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_2( + Engine const& eng, + T min_value, + RangeType range, + BaseResult bmin, + BaseUnsigned brange, + RangeType result, + RangeType mult, + Result const& result_increment_base + ) + { + return sprout::random::detail::generate_uniform_int_true_2_3( + result_increment_base.engine, + min_value, + range, + bmin, + brange, + result, + mult, + result_increment_base.result + ); + } + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_1( + Engine const& eng, + T min_value, + RangeType range, + BaseResult bmin, + BaseUnsigned brange, + RangeType limit, + RangeType result = RangeType(0), + RangeType mult = RangeType(1) + ); + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_1_1( + sprout::random::random_result const& rnd, + T min_value, + RangeType range, + BaseResult bmin, + BaseUnsigned brange, + RangeType limit, + RangeType result, + RangeType mult + ) + { + return mult * RangeType(brange) == range - mult + 1 + ? sprout::random::detail::generate_uniform_int_result{ + static_cast( + result + static_cast(sprout::random::detail::subtract()(rnd.result(), bmin) * mult) + ), + rnd.engine() + } + : sprout::random::detail::generate_uniform_int_true_2_1( + rnd.engine(), + min_value, + range, + bmin, + brange, + limit, + result + static_cast(sprout::random::detail::subtract()(rnd.result(), bmin) * mult), + mult * (RangeType(brange) + RangeType(1)) + ) + ; + } + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_1( + Engine const& eng, + T min_value, + RangeType range, + BaseResult bmin, + BaseUnsigned brange, + RangeType limit, + RangeType result, + RangeType mult + ) + { + return mult <= limit + ? generate_uniform_int_true_2_1_1( + eng(), + min_value, + range, + bmin, + brange, + limit, + result, + mult + ) + : sprout::random::detail::generate_uniform_int_true_2_2( + eng, + min_value, + range, + bmin, + brange, + result, + mult, + sprout::random::detail::generate_uniform_int( + eng, + static_cast(0), + static_cast(range / mult), + std::true_type() + ) + ) + ; + } + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2( + Engine const& eng, + T min_value, + RangeType range, + BaseResult bmin, + BaseUnsigned brange + ) + { + return sprout::random::detail::generate_uniform_int_true_2_1( + eng, + min_value, + range, + bmin, + brange, + range == std::numeric_limits::max() + ? range / (RangeType(brange) + 1) + ( + range % (RangeType(brange) + 1) == RangeType(brange) ? 1 : 0 + ) + : (range + 1) / (RangeType(brange) + 1) + ); + } + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_1_1( + sprout::random::random_result const& rnd, + T min_value, + BaseResult bmin + ) + { + typedef T result_type; + typedef typename std::make_unsigned::type base_unsigned; + return sprout::random::detail::generate_uniform_int_result{ + sprout::random::detail::add()( + base_unsigned(sprout::random::detail::subtract()(rnd.result(), bmin)), + min_value + ), + rnd.engine() + }; + } + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_1( + Engine const& eng, + T min_value, + T max_value, + RangeType range, + BaseResult bmin, + BaseUnsigned brange + ) + { + return range == 0 ? sprout::random::detail::generate_uniform_int_result{min_value, eng} + : brange == range ? sprout::random::detail::generate_uniform_int_true_1_1(eng(), min_value, bmin) + : brange < range ? sprout::random::detail::generate_uniform_int_true_2(eng, min_value, range, bmin, brange) + : sprout::random::detail::generate_uniform_int_true_3(eng, min_value, range, bmin, brange) + ; + } + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int( + Engine const& eng, + T min_value, + T max_value, + std::true_type + ) + { + typedef T result_type; + typedef typename std::make_unsigned::type range_type; + typedef typename Engine::result_type base_result; + typedef typename std::make_unsigned::type base_unsigned; + return sprout::random::detail::generate_uniform_int_true_1( + eng, + min_value, + max_value, + range_type(sprout::random::detail::subtract()(max_value, min_value)), + base_result(eng.min()), + base_unsigned(sprout::random::detail::subtract()(eng.max(), eng.min())) + ); + }; + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_false_1( + Result const& rnd + ) + { + return sprout::random::detail::generate_uniform_int_result{ + rnd.result, + rnd.engine.base() + }; + } + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int( + Engine const& eng, + T min_value, + T max_value, + std::false_type + ) + { + return generate_uniform_int_false_1( + sprout::random::detail::generate_uniform_int( + sprout::random::detail::uniform_int_float(eng), + min_value, + max_value, + std::true_type() + ) + ); + } + template + SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int( + Engine const& eng, + T min_value, + T max_value + ) + { + return generate_uniform_int( + eng, + min_value, + max_value, + std::is_integral() + ); + } + } // namespace detail + // + // uniform_int_distribution + // + template + class uniform_int_distribution { + public: + typedef IntType input_type; + typedef IntType result_type; + private: + static SPROUT_CONSTEXPR IntType arg_check(IntType min_arg, IntType max_arg) { + return min_arg <= max_arg + ? min_arg + : throw "assert(min_arg <= max_arg)" + ; + } + public: + // + // param_type + // + class param_type { + public: + typedef uniform_int_distribution distribution_type; + private: + IntType min_; + IntType max_; + public: + SPROUT_CONSTEXPR param_type() + : min_(0) + , max_(9) + {} + SPROUT_CONSTEXPR explicit param_type(IntType min_arg, IntType max_arg = 9) + : min_(arg_check(min_arg, max_arg)) + , max_(max_arg) + {} + SPROUT_CONSTEXPR IntType a() const { + return min_; + } + SPROUT_CONSTEXPR IntType b() const { + return max_; + } + template + friend std::basic_ostream& operator>>( + std::basic_istream& lhs, + param_type const& rhs + ) + { + return lhs >> rhs.min_ >> std::ws >> rhs.max_; + } + template + friend std::basic_ostream& operator<<( + std::basic_ostream& lhs, + param_type const& rhs + ) + { + return lhs << rhs.min_ << " " << rhs.max_; + } + SPROUT_CONSTEXPR friend bool operator==(param_type const& lhs, param_type const& rhs) { + return lhs.min_ == rhs.min_ && lhs.max_ == rhs.max_; + } + SPROUT_CONSTEXPR friend bool operator!=(param_type const& lhs, param_type const& rhs) { + return !(lhs == rhs); + } + }; + private: + result_type min_; + result_type max_; + private: + template + SPROUT_CONSTEXPR sprout::random::random_result generate(Result const& rnd) const { + return sprout::random::random_result( + rnd.result, + rnd.engine, + *this + ); + } + public: + SPROUT_CONSTEXPR uniform_int_distribution() + : min_(0) + , max_(9) + {} + SPROUT_CONSTEXPR explicit uniform_int_distribution(IntType min_arg, IntType max_arg = 9) + : min_(arg_check(min_arg, max_arg)) + , max_(max_arg) + {} + explicit uniform_int_distribution(param_type const& parm) + : min_(parm.a()) + , max_(parm.b()) + {} + SPROUT_CONSTEXPR result_type a() const { + return min_; + } + SPROUT_CONSTEXPR result_type b() const { + return max_; + } + SPROUT_CONSTEXPR result_type min() const { + return min_; + } + SPROUT_CONSTEXPR result_type max() const { + return max_; + } + SPROUT_CONSTEXPR param_type param() const { + return param_type(min_, max_); + } + void param(param_type const& parm) { + min_ = parm.a(); + max_ = parm.b(); + } + template + SPROUT_CONSTEXPR sprout::random::random_result operator()(Engine const& eng) const { + return generate(sprout::random::detail::generate_uniform_int(eng, min_, max_)); + } + template + friend std::basic_ostream& operator>>( + std::basic_istream& lhs, + uniform_int_distribution const& rhs + ) + { + param_type parm; + return lhs >> parm; + param(parm); + return lhs; + } + template + friend std::basic_ostream& operator<<( + std::basic_ostream& lhs, + uniform_int_distribution const& rhs + ) + { + return lhs << param(); + } + SPROUT_CONSTEXPR friend bool operator==(uniform_int_distribution const& lhs, uniform_int_distribution const& rhs) { + return lhs.param() == rhs.param(); + } + SPROUT_CONSTEXPR friend bool operator!=(uniform_int_distribution const& lhs, uniform_int_distribution const& rhs) { + return !(lhs == rhs); + } + }; + } // namespace random + + using sprout::random::uniform_int_distribution; +} // namespace sprout + +#endif // #ifndef SPROUT_RANDOM_UNIFORM_INT_DISTRIBUTION_HPP + diff --git a/sprout/random/uniform_smallint.hpp b/sprout/random/uniform_smallint.hpp index 41f866df..cb0817cb 100644 --- a/sprout/random/uniform_smallint.hpp +++ b/sprout/random/uniform_smallint.hpp @@ -19,6 +19,13 @@ namespace sprout { public: typedef IntType input_type; typedef IntType result_type; + private: + static SPROUT_CONSTEXPR IntType arg_check(IntType min_arg, IntType max_arg) { + return min_arg <= max_arg + ? min_arg + : throw "assert(min_arg <= max_arg)" + ; + } public: // // param_type @@ -26,13 +33,6 @@ namespace sprout { class param_type { public: typedef uniform_smallint distribution_type; - private: - static SPROUT_CONSTEXPR IntType arg_check(IntType min_arg, IntType max_arg) { - return min_arg <= max_arg - ? min_arg - : throw "assert(min_arg <= max_arg)" - ; - } private: IntType min_; IntType max_; @@ -189,7 +189,7 @@ namespace sprout { , max_(9) {} SPROUT_CONSTEXPR explicit uniform_smallint(IntType min_arg, IntType max_arg = 9) - : min_(min_arg) + : min_(arg_check(min_arg, max_arg)) , max_(max_arg) {} explicit uniform_smallint(param_type const& parm)