/*============================================================================= Copyright (c) 2011-2019 Bolero MURAKAMI https://github.com/bolero-MURAKAMI/Sprout Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #ifndef SPROUT_RANDOM_GEOMETRIC_DISTRIBUTION_HPP #define SPROUT_RANDOM_GEOMETRIC_DISTRIBUTION_HPP #include #include #include #include #include #include #include #include #include #include namespace sprout { namespace random { // // geometric_distribution // template class geometric_distribution { public: typedef RealType input_type; typedef IntType result_type; public: // // param_type // class param_type { public: typedef geometric_distribution distribution_type; private: RealType p_; public: SPROUT_CONSTEXPR param_type() : p_(RealType(0.5)) {} param_type(param_type const&) = default; explicit SPROUT_CONSTEXPR param_type(RealType p_arg) : p_((SPROUT_ASSERT(RealType(0) < p_arg), SPROUT_ASSERT(p_arg < RealType(1)), p_arg)) {} SPROUT_CONSTEXPR RealType p() const SPROUT_NOEXCEPT { return p_; } template friend SPROUT_NON_CONSTEXPR std::basic_istream& operator>>( std::basic_istream& lhs, param_type& rhs ) { RealType p; if (lhs >> p) { if (RealType(0) < p && p < RealType(1)) { rhs.p_ = p; } else { lhs.setstate(std::ios_base::failbit); } } return lhs; } template friend SPROUT_NON_CONSTEXPR std::basic_ostream& operator<<( std::basic_ostream& lhs, param_type const& rhs ) { return lhs << rhs.p_; } friend SPROUT_CONSTEXPR bool operator==(param_type const& lhs, param_type const& rhs) SPROUT_NOEXCEPT { return lhs.p_ == rhs.p_; } friend SPROUT_CONSTEXPR bool operator!=(param_type const& lhs, param_type const& rhs) SPROUT_NOEXCEPT { return !(lhs == rhs); } }; private: static SPROUT_CONSTEXPR RealType init_log_1mp(RealType p) { return sprout::math::log(1 - p); } private: RealType p_; RealType log_1mp_; private: template SPROUT_CONSTEXPR sprout::random::random_result generate_1(Random const& rnd) const { return sprout::random::random_result( static_cast(sprout::math::floor(sprout::math::log(RealType(1) - sprout::random::result(rnd)) / log_1mp_)), sprout::random::next(rnd).engine(), *this ); } template SPROUT_CONSTEXPR sprout::random::random_result generate(Engine const& eng) const { return generate_1(sprout::random::uniform_01()(eng)); } public: SPROUT_CONSTEXPR geometric_distribution() : p_(RealType(0.5)) , log_1mp_(init_log_1mp(RealType(0.5))) {} geometric_distribution(geometric_distribution const&) = default; explicit SPROUT_CONSTEXPR geometric_distribution(RealType p_arg) : p_((SPROUT_ASSERT(RealType(0) < p_arg), SPROUT_ASSERT(p_arg < RealType(1)), p_arg)) , log_1mp_(init_log_1mp(p_arg)) {} explicit SPROUT_CONSTEXPR geometric_distribution(param_type const& parm) : p_(parm.p()) , log_1mp_(init_log_1mp(parm.p())) {} SPROUT_CONSTEXPR result_type p() const SPROUT_NOEXCEPT { return p_; } SPROUT_CONSTEXPR result_type min() const SPROUT_NOEXCEPT { return 0; } SPROUT_CONSTEXPR result_type max() const SPROUT_NOEXCEPT { return sprout::numeric_limits::max(); } SPROUT_CXX14_CONSTEXPR void reset() SPROUT_NOEXCEPT {} SPROUT_CONSTEXPR param_type param() const SPROUT_NOEXCEPT { return param_type(p_); } SPROUT_CXX14_CONSTEXPR void param(param_type const& parm) { p_ = parm.p(); log_1mp_ = init_log_1mp(p_); } template SPROUT_CXX14_CONSTEXPR result_type operator()(Engine& eng) const { return static_cast( sprout::math::floor(sprout::math::log(RealType(1) - static_cast(sprout::random::uniform_01()(eng))) / log_1mp_) ); } template SPROUT_CONSTEXPR sprout::random::random_result const operator()(Engine const& eng) const { return generate(eng); } template SPROUT_CXX14_CONSTEXPR result_type operator()(Engine& eng, param_type const& parm) const { return geometric_distribution(parm)(eng); } template SPROUT_CONSTEXPR sprout::random::random_result const operator()(Engine const& eng, param_type const& parm) const { return geometric_distribution(parm)(eng); } template friend SPROUT_NON_CONSTEXPR std::basic_istream& operator>>( std::basic_istream& lhs, geometric_distribution& rhs ) { param_type parm; if (lhs >> parm) { rhs.param(parm); } return lhs; } template friend SPROUT_NON_CONSTEXPR std::basic_ostream& operator<<( std::basic_ostream& lhs, geometric_distribution const& rhs ) { return lhs << rhs.param(); } friend SPROUT_CONSTEXPR bool operator==(geometric_distribution const& lhs, geometric_distribution const& rhs) SPROUT_NOEXCEPT { return lhs.param() == rhs.param(); } friend SPROUT_CONSTEXPR bool operator!=(geometric_distribution const& lhs, geometric_distribution const& rhs) SPROUT_NOEXCEPT { return !(lhs == rhs); } }; } // namespace random using sprout::random::geometric_distribution; } // namespace sprout #endif // #ifndef SPROUT_RANDOM_GEOMETRIC_DISTRIBUTION_HPP