xref: /freebsd-src/contrib/llvm-project/libcxx/include/__random/binomial_distribution.h (revision 4824e7fd18a1223177218d4aec1b3c6c5c4a444e)
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