annotate PsiCLASS-1.0.2/gamma.cpp @ 0:903fc43d6227 draft default tip

Uploaded
author lsong10
date Fri, 26 Mar 2021 16:52:45 +0000
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
1 #include "gamma.hpp"
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
2
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
3 /** The digamma function in long double precision.
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
4 * @param x the real value of the argument
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
5 * @return the value of the digamma (psi) function at that point
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
6 * @author Richard J. Mathar
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
7 * @since 2005-11-24
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
8 */
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
9 long double digammal(long double x)
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
10 {
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
11 /* force into the interval 1..3 */
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
12 if( x < 0.0L )
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
13 return digammal(1.0L-x)+M_PIl/tanl(M_PIl*(1.0L-x)) ; /* reflection formula */
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
14 else if( x < 1.0L )
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
15 return digammal(1.0L+x)-1.0L/x ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
16 else if ( x == 1.0L)
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
17 return -M_GAMMAl ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
18 else if ( x == 2.0L)
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
19 return 1.0L-M_GAMMAl ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
20 else if ( x == 3.0L)
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
21 return 1.5L-M_GAMMAl ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
22 else if ( x > 3.0L)
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
23 /* duplication formula */
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
24 return 0.5L*(digammal(x/2.0L)+digammal((x+1.0L)/2.0L))+M_LN2l ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
25 else
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
26 {
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
27 /* Just for your information, the following lines contain
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
28 * the Maple source code to re-generate the table that is
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
29 * eventually becoming the Kncoe[] array below
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
30 * interface(prettyprint=0) :
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
31 * Digits := 63 :
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
32 * r := 0 :
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
33 *
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
34 * for l from 1 to 60 do
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
35 * d := binomial(-1/2,l) :
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
36 * r := r+d*(-1)^l*(Zeta(2*l+1) -1) ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
37 * evalf(r) ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
38 * print(%,evalf(1+Psi(1)-r)) ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
39 *o d :
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
40 *
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
41 * for N from 1 to 28 do
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
42 * r := 0 :
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
43 * n := N-1 :
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
44 *
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
45 * for l from iquo(n+3,2) to 70 do
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
46 * d := 0 :
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
47 * for s from 0 to n+1 do
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
48 * d := d+(-1)^s*binomial(n+1,s)*binomial((s-1)/2,l) :
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
49 * od :
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
50 * if 2*l-n > 1 then
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
51 * r := r+d*(-1)^l*(Zeta(2*l-n) -1) :
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
52 * fi :
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
53 * od :
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
54 * print(evalf((-1)^n*2*r)) ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
55 *od :
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
56 *quit :
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
57 */
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
58 static long double Kncoe[] = { .30459198558715155634315638246624251L,
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
59 .72037977439182833573548891941219706L, -.12454959243861367729528855995001087L,
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
60 .27769457331927827002810119567456810e-1L, -.67762371439822456447373550186163070e-2L,
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
61 .17238755142247705209823876688592170e-2L, -.44817699064252933515310345718960928e-3L,
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
62 .11793660000155572716272710617753373e-3L, -.31253894280980134452125172274246963e-4L,
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
63 .83173997012173283398932708991137488e-5L, -.22191427643780045431149221890172210e-5L,
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
64 .59302266729329346291029599913617915e-6L, -.15863051191470655433559920279603632e-6L,
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
65 .42459203983193603241777510648681429e-7L, -.11369129616951114238848106591780146e-7L,
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
66 .304502217295931698401459168423403510e-8L, -.81568455080753152802915013641723686e-9L,
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
67 .21852324749975455125936715817306383e-9L, -.58546491441689515680751900276454407e-10L,
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
68 .15686348450871204869813586459513648e-10L, -.42029496273143231373796179302482033e-11L,
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
69 .11261435719264907097227520956710754e-11L, -.30174353636860279765375177200637590e-12L,
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
70 .80850955256389526647406571868193768e-13L, -.21663779809421233144009565199997351e-13L,
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
71 .58047634271339391495076374966835526e-14L, -.15553767189204733561108869588173845e-14L,
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
72 .41676108598040807753707828039353330e-15L, -.11167065064221317094734023242188463e-15L } ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
73
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
74 register long double Tn_1 = 1.0L ; /* T_{n-1}(x), started at n=1 */
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
75 register long double Tn = x-2.0L ; /* T_{n}(x) , started at n=1 */
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
76 register long double resul = Kncoe[0] + Kncoe[1]*Tn ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
77
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
78 x -= 2.0L ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
79 int n ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
80
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
81 for( n = 2 ; n < sizeof(Kncoe)/sizeof(long double) ;n++)
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
82 {
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
83 const long double Tn1 = 2.0L * x * Tn - Tn_1 ; /* Chebyshev recursion, Eq. 22.7.4 Abramowitz-Stegun */
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
84 resul += Kncoe[n]*Tn1 ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
85 Tn_1 = Tn ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
86 Tn = Tn1 ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
87 }
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
88 return resul ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
89 }
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
90 }
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
91
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
92
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
93
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
94 double trigamma ( double x, int *ifault )
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
95
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
96 //****************************************************************************
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
97 // purpose:
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
98 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
99 // trigamma calculates trigamma(x) = d**2 log(gamma(x)) / dx**2
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
100 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
101 // licensing:
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
102 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
103 // this code is distributed under the gnu lgpl license.
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
104 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
105 // modified:
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
106 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
107 // 19 january 2008
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
108 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
109 // author:
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
110 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
111 // original fortran77 version by be schneider.
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
112 // c++ version by john burkardt.
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
113 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
114 // reference:
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
115 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
116 // be schneider,
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
117 // algorithm as 121:
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
118 // trigamma function,
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
119 // applied statistics,
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
120 // volume 27, number 1, pages 97-99, 1978.
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
121 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
122 // parameters:
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
123 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
124 // input, double x, the argument of the trigamma function.
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
125 // 0 < x.
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
126 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
127 // output, int *ifault, error flag.
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
128 // 0, no error.
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
129 // 1, x <= 0.
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
130 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
131 // output, double trigamma, the value of the trigamma function at x.
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
132 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
133 {
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
134 double a = 0.0001;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
135 double b = 5.0;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
136 double b2 = 0.1666666667;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
137 double b4 = -0.03333333333;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
138 double b6 = 0.02380952381;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
139 double b8 = -0.03333333333;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
140 double value;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
141 double y;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
142 double z;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
143 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
144 // check the input.
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
145 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
146 if ( x <= 0.0 )
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
147 {
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
148 *ifault = 1;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
149 value = 0.0;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
150 return value;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
151 }
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
152
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
153 *ifault = 0;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
154 z = x;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
155 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
156 // use small value approximation if x <= a.
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
157 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
158 if ( x <= a )
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
159 {
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
160 value = 1.0 / x / x;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
161 return value;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
162 }
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
163 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
164 // increase argument to ( x + i ) >= b.
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
165 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
166 value = 0.0;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
167
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
168 while ( z < b )
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
169 {
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
170 value = value + 1.0 / z / z;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
171 z = z + 1.0;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
172 }
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
173 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
174 // apply asymptotic formula if argument is b or greater.
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
175 //
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
176 y = 1.0 / z / z;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
177
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
178 value = value + 0.5 *
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
179 y + ( 1.0 + y * ( b2+ y * ( b4 + y * ( b6+ y * b8 )))) / z;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
180
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
181 return value;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
182 }
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
183
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
184
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
185 double LogGammaDensity( double x, double k, double theta )
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
186 {
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
187 return -k * log( theta ) + ( k - 1 ) * log( x ) - x / theta - lgamma( k ) ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
188 }
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
189
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
190 double MixtureGammaAssignment( double x, double pi, double* k, double *theta )
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
191 {
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
192 if ( pi == 1 )
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
193 return 0 ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
194 else if ( pi == 0 )
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
195 return 1 ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
196
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
197 double lf0 = LogGammaDensity( x, k[0], theta[0] ) ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
198 double lf1 = LogGammaDensity( x, k[1], theta[1] ) ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
199
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
200 return (double)1.0 / ( 1.0 + exp( lf1 + log( 1 - pi ) - lf0 - log( pi ) ) ) ;
903fc43d6227 Uploaded
lsong10
parents:
diff changeset
201 }