williamr@2: /* boost random/gamma_distribution.hpp header file williamr@2: * williamr@2: * Copyright Jens Maurer 2002 williamr@2: * Distributed under the Boost Software License, Version 1.0. (See williamr@2: * accompanying file LICENSE_1_0.txt or copy at williamr@2: * http://www.boost.org/LICENSE_1_0.txt) williamr@2: * williamr@2: * See http://www.boost.org for most recent version including documentation. williamr@2: * williamr@2: * $Id: gamma_distribution.hpp,v 1.9 2004/07/27 03:43:32 dgregor Exp $ williamr@2: * williamr@2: */ williamr@2: williamr@2: #ifndef BOOST_RANDOM_GAMMA_DISTRIBUTION_HPP williamr@2: #define BOOST_RANDOM_GAMMA_DISTRIBUTION_HPP williamr@2: williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: williamr@2: namespace boost { williamr@2: williamr@2: // Knuth williamr@2: template williamr@2: class gamma_distribution williamr@2: { williamr@2: public: williamr@2: typedef RealType input_type; williamr@2: typedef RealType result_type; williamr@2: williamr@2: #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS williamr@2: BOOST_STATIC_ASSERT(!std::numeric_limits::is_integer); williamr@2: #endif williamr@2: williamr@2: explicit gamma_distribution(const result_type& alpha = result_type(1)) williamr@2: : _exp(result_type(1)), _alpha(alpha) williamr@2: { williamr@2: assert(alpha > result_type(0)); williamr@2: init(); williamr@2: } williamr@2: williamr@2: // compiler-generated copy ctor and assignment operator are fine williamr@2: williamr@2: RealType alpha() const { return _alpha; } williamr@2: williamr@2: void reset() { _exp.reset(); } williamr@2: williamr@2: template williamr@2: result_type operator()(Engine& eng) williamr@2: { williamr@2: #ifndef BOOST_NO_STDC_NAMESPACE williamr@2: // allow for Koenig lookup williamr@2: using std::tan; using std::sqrt; using std::exp; using std::log; williamr@2: using std::pow; williamr@2: #endif williamr@2: if(_alpha == result_type(1)) { williamr@2: return _exp(eng); williamr@2: } else if(_alpha > result_type(1)) { williamr@2: // Can we have a boost::mathconst please? williamr@2: const result_type pi = result_type(3.14159265358979323846); williamr@2: for(;;) { williamr@2: result_type y = tan(pi * eng()); williamr@2: result_type x = sqrt(result_type(2)*_alpha-result_type(1))*y williamr@2: + _alpha-result_type(1); williamr@2: if(x <= result_type(0)) williamr@2: continue; williamr@2: if(eng() > williamr@2: (result_type(1)+y*y) * exp((_alpha-result_type(1)) williamr@2: *log(x/(_alpha-result_type(1))) williamr@2: - sqrt(result_type(2)*_alpha williamr@2: -result_type(1))*y)) williamr@2: continue; williamr@2: return x; williamr@2: } williamr@2: } else /* alpha < 1.0 */ { williamr@2: for(;;) { williamr@2: result_type u = eng(); williamr@2: result_type y = _exp(eng); williamr@2: result_type x, q; williamr@2: if(u < _p) { williamr@2: x = exp(-y/_alpha); williamr@2: q = _p*exp(-x); williamr@2: } else { williamr@2: x = result_type(1)+y; williamr@2: q = _p + (result_type(1)-_p) * pow(x, _alpha-result_type(1)); williamr@2: } williamr@2: if(u >= q) williamr@2: continue; williamr@2: return x; williamr@2: } williamr@2: } williamr@2: } williamr@2: williamr@2: #if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) williamr@2: template williamr@2: friend std::basic_ostream& williamr@2: operator<<(std::basic_ostream& os, const gamma_distribution& gd) williamr@2: { williamr@2: os << gd._alpha; williamr@2: return os; williamr@2: } williamr@2: williamr@2: template williamr@2: friend std::basic_istream& williamr@2: operator>>(std::basic_istream& is, gamma_distribution& gd) williamr@2: { williamr@2: is >> std::ws >> gd._alpha; williamr@2: gd.init(); williamr@2: return is; williamr@2: } williamr@2: #endif williamr@2: williamr@2: private: williamr@2: void init() williamr@2: { williamr@2: #ifndef BOOST_NO_STDC_NAMESPACE williamr@2: // allow for Koenig lookup williamr@2: using std::exp; williamr@2: #endif williamr@2: _p = exp(result_type(1)) / (_alpha + exp(result_type(1))); williamr@2: } williamr@2: williamr@2: exponential_distribution _exp; williamr@2: result_type _alpha; williamr@2: // some data precomputed from the parameters williamr@2: result_type _p; williamr@2: }; williamr@2: williamr@2: } // namespace boost williamr@2: williamr@2: #endif // BOOST_RANDOM_GAMMA_DISTRIBUTION_HPP