From 4a345e82591404eedf48b8df11cd7508de0b4af1 Mon Sep 17 00:00:00 2001 From: bolero-MURAKAMI Date: Thu, 29 Sep 2011 22:46:32 +0900 Subject: [PATCH] =?UTF-8?q?random=20=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sprout/random.hpp | 5 + .../random/detail/signed_unsigned_tools.hpp | 63 +++++ sprout/random/linear_congruential.hpp | 21 +- sprout/random/random_result.hpp | 127 +++++++++ sprout/random/uniform_01.hpp | 91 +++++++ sprout/random/uniform_smallint.hpp | 245 ++++++++++++++++++ 6 files changed, 544 insertions(+), 8 deletions(-) create mode 100644 sprout/random/detail/signed_unsigned_tools.hpp create mode 100644 sprout/random/random_result.hpp create mode 100644 sprout/random/uniform_01.hpp create mode 100644 sprout/random/uniform_smallint.hpp diff --git a/sprout/random.hpp b/sprout/random.hpp index af3555dd..1a6a9396 100644 --- a/sprout/random.hpp +++ b/sprout/random.hpp @@ -1,7 +1,12 @@ #ifndef SPROUT_RANDOM_HPP #define SPROUT_RANDOM_HPP +#include +#include #include +#include +#include #endif // #ifndef SPROUT_RANDOM_HPP + diff --git a/sprout/random/detail/signed_unsigned_tools.hpp b/sprout/random/detail/signed_unsigned_tools.hpp new file mode 100644 index 00000000..cd8eeb96 --- /dev/null +++ b/sprout/random/detail/signed_unsigned_tools.hpp @@ -0,0 +1,63 @@ +#ifndef SPROUT_RANDOM_DETAIL_SIGNED_UNSIGNED_TOOLS_HPP +#define SPROUT_RANDOM_DETAIL_SIGNED_UNSIGNED_TOOLS_HPP + +#include +#include +#include + +namespace sprout { + namespace random { + namespace detail { + template::is_signed> + struct subtract {}; + template + struct subtract { + public: + typedef T result_type; + public: + SPROUT_CONSTEXPR result_type operator()(T x, T y) const { + return x - y; + } + }; + template + struct subtract { + public: + typedef typename std::make_unsigned::type result_type; + public: + SPROUT_CONSTEXPR result_type operator()(T x, T y) const { + return y >= 0 ? result_type(x) - result_type(y) + : x >= 0 ? result_type(x) + result_type(-(y + 1)) + 1 + : result_type(x - y) + ; + } + }; + + template::is_signed> + struct add {}; + template + struct add { + public: + typedef T2 result_type; + public: + SPROUT_CONSTEXPR result_type operator()(T1 x, T2 y) const { + return T2(x) + y; + } + }; + template + struct add { + public: + typedef T2 result_type; + public: + SPROUT_CONSTEXPR result_type operator()(T1 x, T2 y) const { + return y >= 0 ? T2(x) + y + : x >= T1(-(y + 1)) ? T2(x - T1(-(y + 1)) - 1) + : T2(x) + y + ; + } + }; + } // namespace detail + } // namespace random +} // namespace sprout + +#endif // SPROUT_RANDOM_DETAIL_SIGNED_UNSIGNED_TOOLS_HPP + diff --git a/sprout/random/linear_congruential.hpp b/sprout/random/linear_congruential.hpp index 655f6eef..ac41ba0f 100644 --- a/sprout/random/linear_congruential.hpp +++ b/sprout/random/linear_congruential.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace sprout { namespace random { @@ -29,9 +30,10 @@ namespace sprout { static_assert(m == 0 || c < m, "m == 0 || c < m"); private: static SPROUT_CONSTEXPR IntType init_seed_3(IntType const& x0) { - //static_assert(x0 >= static_min(), "x0 >= static_min()"); - //static_assert(x0 <= static_max(), "x0 <= static_max()"); - return x0; + return x0 >= static_min() && x0 <= static_max() + ? x0 + : throw "assert(x0 >= static_min() && x0 <= static_max())" + ; } static SPROUT_CONSTEXPR IntType init_seed_2(IntType const& x0) { return init_seed_3(increment == 0 && x0 == 0 ? 1 : x0); @@ -55,6 +57,12 @@ namespace sprout { SPROUT_CONSTEXPR linear_congruential_engine(IntType const& x, private_constructor_tag) : x_(x) {} + SPROUT_CONSTEXPR sprout::random::random_result generate(result_type result) const { + return sprout::random::random_result( + result, + linear_congruential_engine(result, private_constructor_tag()) + ); + } public: SPROUT_CONSTEXPR linear_congruential_engine() : x_(init_seed(default_seed)) @@ -68,11 +76,8 @@ namespace sprout { SPROUT_CONSTEXPR result_type max() const { return static_max(); } - SPROUT_CONSTEXPR result_type operator()() const { - return sprout::random::detail::const_mod::mult_add(a, x_, c); - } - SPROUT_CONSTEXPR linear_congruential_engine next() const { - return linear_congruential_engine(operator()(), private_constructor_tag()); + SPROUT_CONSTEXPR sprout::random::random_result operator()() const { + return generate(sprout::random::detail::const_mod::mult_add(a, x_, c)); } friend SPROUT_CONSTEXPR bool operator==(linear_congruential_engine const& lhs, linear_congruential_engine const& rhs) { return lhs.x_ == rhs.x_; diff --git a/sprout/random/random_result.hpp b/sprout/random/random_result.hpp new file mode 100644 index 00000000..99f5e730 --- /dev/null +++ b/sprout/random/random_result.hpp @@ -0,0 +1,127 @@ +#ifndef SPROUT_RANDOM_RANDOM_RESULT_HPP +#define SPROUT_RANDOM_RANDOM_RESULT_HPP + +#include +#include + +namespace sprout { + namespace random { + // + // random_result + // + template + class random_result; + + template + class random_result< + Engine, + Distribution, + typename std::enable_if::value>::type + > { + public: + typedef Engine engine_type; + typedef Distribution distribution_type; + typedef typename distribution_type::result_type result_type; + private: + result_type result_; + engine_type engine_; + distribution_type distribution_; + public: + SPROUT_CONSTEXPR random_result( + result_type result, + engine_type const& engine, + distribution_type const& distribution + ) + : result_(result) + , engine_(engine) + , distribution_(distribution) + {} + SPROUT_CONSTEXPR operator result_type() const { + return result_; + } + SPROUT_CONSTEXPR result_type operator*() const { + return result_; + } + SPROUT_CONSTEXPR random_result operator()() const { + return distribution_(engine_); + } + result_type& result() { + return result_; + } + SPROUT_CONSTEXPR result_type const& result() const { + return result_; + } + engine_type& engine() { + return engine_; + } + SPROUT_CONSTEXPR engine_type const& engine() const { + return engine_; + } + distribution_type& distribution() { + return distribution_; + } + SPROUT_CONSTEXPR distribution_type const& distribution() const { + return distribution_; + } + SPROUT_CONSTEXPR result_type min() const { + return distribution_.min(); + } + SPROUT_CONSTEXPR result_type max() const { + return distribution_.max(); + } + }; + template + class random_result< + Engine, + Distribution, + typename std::enable_if::value>::type + > { + public: + typedef Engine engine_type; + typedef typename engine_type::result_type result_type; + private: + result_type result_; + engine_type engine_; + public: + SPROUT_CONSTEXPR random_result( + result_type result, + engine_type const& engine + ) + : result_(result) + , engine_(engine) + {} + SPROUT_CONSTEXPR operator result_type() const { + return result_; + } + SPROUT_CONSTEXPR result_type operator*() const { + return result_; + } + SPROUT_CONSTEXPR random_result operator()() const { + return engine_(); + } + result_type& result() { + return result_; + } + SPROUT_CONSTEXPR result_type const& result() const { + return result_; + } + engine_type& engine() { + return engine_; + } + SPROUT_CONSTEXPR engine_type const& engine() const { + return engine_; + } + SPROUT_CONSTEXPR result_type min() const { + return engine_.min(); + } + SPROUT_CONSTEXPR result_type max() const { + return engine_.max(); + } + }; + } // namespace random + + using sprout::random::random_result; +} // namespace sprout + +#endif // #ifndef SPROUT_RANDOM_RANDOM_RESULT_HPP + diff --git a/sprout/random/uniform_01.hpp b/sprout/random/uniform_01.hpp new file mode 100644 index 00000000..3adc08a6 --- /dev/null +++ b/sprout/random/uniform_01.hpp @@ -0,0 +1,91 @@ +#ifndef SPROUT_RANDOM_UNIFORM_01_HPP +#define SPROUT_RANDOM_UNIFORM_01_HPP + +#include +#include +#include +#include + +namespace sprout { + namespace random { + // + // uniform_01 + // + template + class uniform_01 { + public: + typedef RealType input_type; + typedef RealType result_type; + private: + template + SPROUT_CONSTEXPR sprout::random::random_result generate_1( + Engine const& eng, + sprout::random::random_result const& rnd, + result_type result + ) const + { + return result < result_type(1) + ? sprout::random::random_result(result, rnd.engine(), *this) + : operator()(rnd.engine()) + ; + } + template + SPROUT_CONSTEXPR sprout::random::random_result generate( + Engine const& eng, + sprout::random::random_result const& rnd + ) const + { + typedef typename Engine::result_type base_result; + return generate_1( + eng, + rnd, + result_type(rnd.result() - eng.min()) * ( + result_type(1) / ( + result_type(eng.max() - eng.min()) + result_type( + std::numeric_limits::is_integer ? 1 : 0 + ) + ) + ) + ); + } + public: + SPROUT_CONSTEXPR result_type min() const { + return result_type(0); + } + SPROUT_CONSTEXPR result_type max() const { + return result_type(1); + } + template + SPROUT_CONSTEXPR sprout::random::random_result operator()(Engine const& eng) const { + return generate(eng, eng()); + } + template + friend std::basic_ostream& operator>>( + std::basic_istream& lhs, + uniform_01 const& rhs + ) + { + return lhs; + } + template + friend std::basic_ostream& operator<<( + std::basic_ostream& lhs, + uniform_01 const& rhs + ) + { + return lhs; + } + SPROUT_CONSTEXPR friend bool operator==(uniform_01 const& lhs, uniform_01 const& rhs) { + return true; + } + SPROUT_CONSTEXPR friend bool operator!=(uniform_01 const& lhs, uniform_01 const& rhs) { + return !(lhs == rhs); + } + }; + } // namespace random + + using sprout::random::uniform_01; +} // namespace sprout + +#endif // #ifndef SPROUT_RANDOM_UNIFORM_01_HPP + diff --git a/sprout/random/uniform_smallint.hpp b/sprout/random/uniform_smallint.hpp new file mode 100644 index 00000000..92e6ea51 --- /dev/null +++ b/sprout/random/uniform_smallint.hpp @@ -0,0 +1,245 @@ +#ifndef SPROUT_RANDOM_UNIFORM_SMALLINT_HPP +#define SPROUT_RANDOM_UNIFORM_SMALLINT_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace sprout { + namespace random { + // + // uniform_smallint + // + template + class uniform_smallint { + public: + typedef IntType input_type; + typedef IntType result_type; + public: + // + // param_type + // + 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_; + public: + SPROUT_CONSTEXPR param_type(IntType min_arg = 0, 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_true_2( + Engine const& eng, + sprout::random::random_result const& rnd, + RangeType range, + BaseUnsigned base_range, + BaseUnsigned val + ) const + { + return range >= base_range + ? sprout::random::random_result( + sprout::random::detail::add()(static_cast(val), min_), + rnd.engine(), + *this + ) + : sprout::random::random_result( + sprout::random::detail::add()(static_cast(val % (static_cast(range) + 1)), min_), + rnd.engine(), + *this + ) + ; + } + template + SPROUT_CONSTEXPR sprout::random::random_result generate_true_1( + Engine const& eng, + sprout::random::random_result const& rnd, + RangeType range, + BaseUnsigned base_range + ) const + { + typedef typename Engine::result_type base_result; + return generate_true_2( + eng, + rnd, + range, + base_range, + BaseUnsigned(sprout::random::detail::subtract()(rnd.result(), eng.min())) + ); + } + template + SPROUT_CONSTEXPR sprout::random::random_result generate( + Engine const& eng, + std::true_type + ) const + { + typedef typename Engine::result_type base_result; + typedef typename std::make_unsigned::type base_unsigned; + typedef typename std::make_unsigned::type range_type; + return generate_true_1( + eng, + eng(), + range_type(sprout::random::detail::subtract()(max_, min_)), + base_unsigned(sprout::random::detail::subtract()(eng.max(), eng.min())) + ); + } + template + SPROUT_CONSTEXPR sprout::random::random_result generate_false_2( + Engine const& eng, + sprout::random::random_result > const& rnd, + RangeType range, + RangeType offset + ) const + { + return offset > range + ? sprout::random::random_result( + max_, + rnd.engine(), + *this + ) + : sprout::random::random_result( + sprout::random::detail::add()(offset , min_), + rnd.engine(), + *this + ) + ; + } + template + SPROUT_CONSTEXPR sprout::random::random_result generate_false_1( + Engine const& eng, + sprout::random::random_result > const& rnd, + RangeType range + ) const + { + typedef typename Engine::result_type base_result; + return generate_false_2( + eng, + rnd, + RangeType(sprout::random::detail::subtract()(max_, min_)), + RangeType(static_cast(rnd.result() * (static_cast(range) + 1))) + ); + } + template + SPROUT_CONSTEXPR sprout::random::random_result generate( + Engine const& eng, + std::false_type + ) const + { + typedef typename Engine::result_type base_result; + typedef typename std::make_unsigned::type range_type; + return generate_false_1( + eng, + sprout::random::uniform_01()(eng), + range_type(sprout::random::detail::subtract()(max_, min_)) + ); + } + public: + SPROUT_CONSTEXPR explicit uniform_smallint(IntType min_arg = 0, IntType max_arg = 9) + : min_(min_arg), max_(max_arg) + {} + explicit uniform_smallint(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 { + typedef typename Engine::result_type base_result; + return generate(eng, typename std::is_integral::type()); + } + template + friend std::basic_ostream& operator>>( + std::basic_istream& lhs, + uniform_smallint const& rhs + ) + { + param_type parm; + return lhs >> parm; + param(parm); + return lhs; + } + template + friend std::basic_ostream& operator<<( + std::basic_ostream& lhs, + uniform_smallint const& rhs + ) + { + return lhs << param(); + } + SPROUT_CONSTEXPR friend bool operator==(uniform_smallint const& lhs, uniform_smallint const& rhs) { + return lhs.param() == rhs.param(); + } + SPROUT_CONSTEXPR friend bool operator!=(uniform_smallint const& lhs, uniform_smallint const& rhs) { + return !(lhs == rhs); + } + }; + } // namespace random + + using sprout::random::uniform_smallint; +} // namespace sprout + +#endif // #ifndef SPROUT_RANDOM_UNIFORM_SMALLINT_HPP +