1*4824e7fdSDimitry Andric //===----------------------------------------------------------------------===// 2*4824e7fdSDimitry Andric // 3*4824e7fdSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*4824e7fdSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*4824e7fdSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*4824e7fdSDimitry Andric // 7*4824e7fdSDimitry Andric //===----------------------------------------------------------------------===// 8*4824e7fdSDimitry Andric 9*4824e7fdSDimitry Andric #ifndef _LIBCPP___RANDOM_BINOMIAL_DISTRIBUTION_H 10*4824e7fdSDimitry Andric #define _LIBCPP___RANDOM_BINOMIAL_DISTRIBUTION_H 11*4824e7fdSDimitry Andric 12*4824e7fdSDimitry Andric #include <__config> 13*4824e7fdSDimitry Andric #include <__random/uniform_real_distribution.h> 14*4824e7fdSDimitry Andric #include <cmath> 15*4824e7fdSDimitry Andric #include <iosfwd> 16*4824e7fdSDimitry Andric 17*4824e7fdSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 18*4824e7fdSDimitry Andric #pragma GCC system_header 19*4824e7fdSDimitry Andric #endif 20*4824e7fdSDimitry Andric 21*4824e7fdSDimitry Andric _LIBCPP_PUSH_MACROS 22*4824e7fdSDimitry Andric #include <__undef_macros> 23*4824e7fdSDimitry Andric 24*4824e7fdSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 25*4824e7fdSDimitry Andric 26*4824e7fdSDimitry Andric template<class _IntType = int> 27*4824e7fdSDimitry Andric class _LIBCPP_TEMPLATE_VIS binomial_distribution 28*4824e7fdSDimitry Andric { 29*4824e7fdSDimitry Andric public: 30*4824e7fdSDimitry Andric // types 31*4824e7fdSDimitry Andric typedef _IntType result_type; 32*4824e7fdSDimitry Andric 33*4824e7fdSDimitry Andric class _LIBCPP_TEMPLATE_VIS param_type 34*4824e7fdSDimitry Andric { 35*4824e7fdSDimitry Andric result_type __t_; 36*4824e7fdSDimitry Andric double __p_; 37*4824e7fdSDimitry Andric double __pr_; 38*4824e7fdSDimitry Andric double __odds_ratio_; 39*4824e7fdSDimitry Andric result_type __r0_; 40*4824e7fdSDimitry Andric public: 41*4824e7fdSDimitry Andric typedef binomial_distribution distribution_type; 42*4824e7fdSDimitry Andric 43*4824e7fdSDimitry Andric explicit param_type(result_type __t = 1, double __p = 0.5); 44*4824e7fdSDimitry Andric 45*4824e7fdSDimitry Andric _LIBCPP_INLINE_VISIBILITY 46*4824e7fdSDimitry Andric result_type t() const {return __t_;} 47*4824e7fdSDimitry Andric _LIBCPP_INLINE_VISIBILITY 48*4824e7fdSDimitry Andric double p() const {return __p_;} 49*4824e7fdSDimitry Andric 50*4824e7fdSDimitry Andric friend _LIBCPP_INLINE_VISIBILITY 51*4824e7fdSDimitry Andric bool operator==(const param_type& __x, const param_type& __y) 52*4824e7fdSDimitry Andric {return __x.__t_ == __y.__t_ && __x.__p_ == __y.__p_;} 53*4824e7fdSDimitry Andric friend _LIBCPP_INLINE_VISIBILITY 54*4824e7fdSDimitry Andric bool operator!=(const param_type& __x, const param_type& __y) 55*4824e7fdSDimitry Andric {return !(__x == __y);} 56*4824e7fdSDimitry Andric 57*4824e7fdSDimitry Andric friend class binomial_distribution; 58*4824e7fdSDimitry Andric }; 59*4824e7fdSDimitry Andric 60*4824e7fdSDimitry Andric private: 61*4824e7fdSDimitry Andric param_type __p_; 62*4824e7fdSDimitry Andric 63*4824e7fdSDimitry Andric public: 64*4824e7fdSDimitry Andric // constructors and reset functions 65*4824e7fdSDimitry Andric #ifndef _LIBCPP_CXX03_LANG 66*4824e7fdSDimitry Andric _LIBCPP_INLINE_VISIBILITY 67*4824e7fdSDimitry Andric binomial_distribution() : binomial_distribution(1) {} 68*4824e7fdSDimitry Andric _LIBCPP_INLINE_VISIBILITY 69*4824e7fdSDimitry Andric explicit binomial_distribution(result_type __t, double __p = 0.5) 70*4824e7fdSDimitry Andric : __p_(param_type(__t, __p)) {} 71*4824e7fdSDimitry Andric #else 72*4824e7fdSDimitry Andric _LIBCPP_INLINE_VISIBILITY 73*4824e7fdSDimitry Andric explicit binomial_distribution(result_type __t = 1, double __p = 0.5) 74*4824e7fdSDimitry Andric : __p_(param_type(__t, __p)) {} 75*4824e7fdSDimitry Andric #endif 76*4824e7fdSDimitry Andric _LIBCPP_INLINE_VISIBILITY 77*4824e7fdSDimitry Andric explicit binomial_distribution(const param_type& __p) : __p_(__p) {} 78*4824e7fdSDimitry Andric _LIBCPP_INLINE_VISIBILITY 79*4824e7fdSDimitry Andric void reset() {} 80*4824e7fdSDimitry Andric 81*4824e7fdSDimitry Andric // generating functions 82*4824e7fdSDimitry Andric template<class _URNG> 83*4824e7fdSDimitry Andric _LIBCPP_INLINE_VISIBILITY 84*4824e7fdSDimitry Andric result_type operator()(_URNG& __g) 85*4824e7fdSDimitry Andric {return (*this)(__g, __p_);} 86*4824e7fdSDimitry Andric template<class _URNG> result_type operator()(_URNG& __g, const param_type& __p); 87*4824e7fdSDimitry Andric 88*4824e7fdSDimitry Andric // property functions 89*4824e7fdSDimitry Andric _LIBCPP_INLINE_VISIBILITY 90*4824e7fdSDimitry Andric result_type t() const {return __p_.t();} 91*4824e7fdSDimitry Andric _LIBCPP_INLINE_VISIBILITY 92*4824e7fdSDimitry Andric double p() const {return __p_.p();} 93*4824e7fdSDimitry Andric 94*4824e7fdSDimitry Andric _LIBCPP_INLINE_VISIBILITY 95*4824e7fdSDimitry Andric param_type param() const {return __p_;} 96*4824e7fdSDimitry Andric _LIBCPP_INLINE_VISIBILITY 97*4824e7fdSDimitry Andric void param(const param_type& __p) {__p_ = __p;} 98*4824e7fdSDimitry Andric 99*4824e7fdSDimitry Andric _LIBCPP_INLINE_VISIBILITY 100*4824e7fdSDimitry Andric result_type min() const {return 0;} 101*4824e7fdSDimitry Andric _LIBCPP_INLINE_VISIBILITY 102*4824e7fdSDimitry Andric result_type max() const {return t();} 103*4824e7fdSDimitry Andric 104*4824e7fdSDimitry Andric friend _LIBCPP_INLINE_VISIBILITY 105*4824e7fdSDimitry Andric bool operator==(const binomial_distribution& __x, 106*4824e7fdSDimitry Andric const binomial_distribution& __y) 107*4824e7fdSDimitry Andric {return __x.__p_ == __y.__p_;} 108*4824e7fdSDimitry Andric friend _LIBCPP_INLINE_VISIBILITY 109*4824e7fdSDimitry Andric bool operator!=(const binomial_distribution& __x, 110*4824e7fdSDimitry Andric const binomial_distribution& __y) 111*4824e7fdSDimitry Andric {return !(__x == __y);} 112*4824e7fdSDimitry Andric }; 113*4824e7fdSDimitry Andric 114*4824e7fdSDimitry Andric #ifndef _LIBCPP_MSVCRT_LIKE 115*4824e7fdSDimitry Andric extern "C" double lgamma_r(double, int *); 116*4824e7fdSDimitry Andric #endif 117*4824e7fdSDimitry Andric 118*4824e7fdSDimitry Andric inline _LIBCPP_INLINE_VISIBILITY double __libcpp_lgamma(double __d) { 119*4824e7fdSDimitry Andric #if defined(_LIBCPP_MSVCRT_LIKE) 120*4824e7fdSDimitry Andric return lgamma(__d); 121*4824e7fdSDimitry Andric #else 122*4824e7fdSDimitry Andric int __sign; 123*4824e7fdSDimitry Andric return lgamma_r(__d, &__sign); 124*4824e7fdSDimitry Andric #endif 125*4824e7fdSDimitry Andric } 126*4824e7fdSDimitry Andric 127*4824e7fdSDimitry Andric template<class _IntType> 128*4824e7fdSDimitry Andric binomial_distribution<_IntType>::param_type::param_type(result_type __t, double __p) 129*4824e7fdSDimitry Andric : __t_(__t), __p_(__p) 130*4824e7fdSDimitry Andric { 131*4824e7fdSDimitry Andric if (0 < __p_ && __p_ < 1) 132*4824e7fdSDimitry Andric { 133*4824e7fdSDimitry Andric __r0_ = static_cast<result_type>((__t_ + 1) * __p_); 134*4824e7fdSDimitry Andric __pr_ = _VSTD::exp(__libcpp_lgamma(__t_ + 1.) - 135*4824e7fdSDimitry Andric __libcpp_lgamma(__r0_ + 1.) - 136*4824e7fdSDimitry Andric __libcpp_lgamma(__t_ - __r0_ + 1.) + __r0_ * _VSTD::log(__p_) + 137*4824e7fdSDimitry Andric (__t_ - __r0_) * _VSTD::log(1 - __p_)); 138*4824e7fdSDimitry Andric __odds_ratio_ = __p_ / (1 - __p_); 139*4824e7fdSDimitry Andric } 140*4824e7fdSDimitry Andric } 141*4824e7fdSDimitry Andric 142*4824e7fdSDimitry Andric // Reference: Kemp, C.D. (1986). `A modal method for generating binomial 143*4824e7fdSDimitry Andric // variables', Commun. Statist. - Theor. Meth. 15(3), 805-813. 144*4824e7fdSDimitry Andric template<class _IntType> 145*4824e7fdSDimitry Andric template<class _URNG> 146*4824e7fdSDimitry Andric _IntType 147*4824e7fdSDimitry Andric binomial_distribution<_IntType>::operator()(_URNG& __g, const param_type& __pr) 148*4824e7fdSDimitry Andric { 149*4824e7fdSDimitry Andric if (__pr.__t_ == 0 || __pr.__p_ == 0) 150*4824e7fdSDimitry Andric return 0; 151*4824e7fdSDimitry Andric if (__pr.__p_ == 1) 152*4824e7fdSDimitry Andric return __pr.__t_; 153*4824e7fdSDimitry Andric uniform_real_distribution<double> __gen; 154*4824e7fdSDimitry Andric double __u = __gen(__g) - __pr.__pr_; 155*4824e7fdSDimitry Andric if (__u < 0) 156*4824e7fdSDimitry Andric return __pr.__r0_; 157*4824e7fdSDimitry Andric double __pu = __pr.__pr_; 158*4824e7fdSDimitry Andric double __pd = __pu; 159*4824e7fdSDimitry Andric result_type __ru = __pr.__r0_; 160*4824e7fdSDimitry Andric result_type __rd = __ru; 161*4824e7fdSDimitry Andric while (true) 162*4824e7fdSDimitry Andric { 163*4824e7fdSDimitry Andric bool __break = true; 164*4824e7fdSDimitry Andric if (__rd >= 1) 165*4824e7fdSDimitry Andric { 166*4824e7fdSDimitry Andric __pd *= __rd / (__pr.__odds_ratio_ * (__pr.__t_ - __rd + 1)); 167*4824e7fdSDimitry Andric __u -= __pd; 168*4824e7fdSDimitry Andric __break = false; 169*4824e7fdSDimitry Andric if (__u < 0) 170*4824e7fdSDimitry Andric return __rd - 1; 171*4824e7fdSDimitry Andric } 172*4824e7fdSDimitry Andric if ( __rd != 0 ) 173*4824e7fdSDimitry Andric --__rd; 174*4824e7fdSDimitry Andric ++__ru; 175*4824e7fdSDimitry Andric if (__ru <= __pr.__t_) 176*4824e7fdSDimitry Andric { 177*4824e7fdSDimitry Andric __pu *= (__pr.__t_ - __ru + 1) * __pr.__odds_ratio_ / __ru; 178*4824e7fdSDimitry Andric __u -= __pu; 179*4824e7fdSDimitry Andric __break = false; 180*4824e7fdSDimitry Andric if (__u < 0) 181*4824e7fdSDimitry Andric return __ru; 182*4824e7fdSDimitry Andric } 183*4824e7fdSDimitry Andric if (__break) 184*4824e7fdSDimitry Andric return 0; 185*4824e7fdSDimitry Andric } 186*4824e7fdSDimitry Andric } 187*4824e7fdSDimitry Andric 188*4824e7fdSDimitry Andric template <class _CharT, class _Traits, class _IntType> 189*4824e7fdSDimitry Andric basic_ostream<_CharT, _Traits>& 190*4824e7fdSDimitry Andric operator<<(basic_ostream<_CharT, _Traits>& __os, 191*4824e7fdSDimitry Andric const binomial_distribution<_IntType>& __x) 192*4824e7fdSDimitry Andric { 193*4824e7fdSDimitry Andric __save_flags<_CharT, _Traits> __lx(__os); 194*4824e7fdSDimitry Andric typedef basic_ostream<_CharT, _Traits> _OStream; 195*4824e7fdSDimitry Andric __os.flags(_OStream::dec | _OStream::left | _OStream::fixed | 196*4824e7fdSDimitry Andric _OStream::scientific); 197*4824e7fdSDimitry Andric _CharT __sp = __os.widen(' '); 198*4824e7fdSDimitry Andric __os.fill(__sp); 199*4824e7fdSDimitry Andric return __os << __x.t() << __sp << __x.p(); 200*4824e7fdSDimitry Andric } 201*4824e7fdSDimitry Andric 202*4824e7fdSDimitry Andric template <class _CharT, class _Traits, class _IntType> 203*4824e7fdSDimitry Andric basic_istream<_CharT, _Traits>& 204*4824e7fdSDimitry Andric operator>>(basic_istream<_CharT, _Traits>& __is, 205*4824e7fdSDimitry Andric binomial_distribution<_IntType>& __x) 206*4824e7fdSDimitry Andric { 207*4824e7fdSDimitry Andric typedef binomial_distribution<_IntType> _Eng; 208*4824e7fdSDimitry Andric typedef typename _Eng::result_type result_type; 209*4824e7fdSDimitry Andric typedef typename _Eng::param_type param_type; 210*4824e7fdSDimitry Andric __save_flags<_CharT, _Traits> __lx(__is); 211*4824e7fdSDimitry Andric typedef basic_istream<_CharT, _Traits> _Istream; 212*4824e7fdSDimitry Andric __is.flags(_Istream::dec | _Istream::skipws); 213*4824e7fdSDimitry Andric result_type __t; 214*4824e7fdSDimitry Andric double __p; 215*4824e7fdSDimitry Andric __is >> __t >> __p; 216*4824e7fdSDimitry Andric if (!__is.fail()) 217*4824e7fdSDimitry Andric __x.param(param_type(__t, __p)); 218*4824e7fdSDimitry Andric return __is; 219*4824e7fdSDimitry Andric } 220*4824e7fdSDimitry Andric 221*4824e7fdSDimitry Andric _LIBCPP_END_NAMESPACE_STD 222*4824e7fdSDimitry Andric 223*4824e7fdSDimitry Andric _LIBCPP_POP_MACROS 224*4824e7fdSDimitry Andric 225*4824e7fdSDimitry Andric #endif // _LIBCPP___RANDOM_BINOMIAL_DISTRIBUTION_H 226