annotate digamma.c @ 755:37c2b9cce23a multiprobeLSH

Adding mkc_lsh_update branch, trunk candidate with improved LSH: merged trunk 1095 and branch multiprobe_lsh
author mas01mc
date Thu, 25 Nov 2010 13:42:40 +0000
parents 3e1137d12ecc
children
rev   line source
mas01mc@742 1 /*************************************
mas01mc@742 2 An ANSI-C implementation of the digamma-function for real arguments based
mas01mc@742 3 on the Chebyshev expansion proposed in appendix E of
mas01mc@742 4 http://arXiv.org/abs/math.CA/0403344 . For other implementations see
mas01mc@742 5 the GSL implementation for Psi(Digamma) in
mas01mc@742 6 http://www.gnu.org/software/gsl/manual/gsl-ref_toc.html
mas01mc@742 7
mas01mc@742 8 Richard J. Mathar, 2005-11-24
mas01mc@742 9 http://www.strw.leidenuniv.nl/~mathar/progs/digamma.c
mas01mc@742 10 **************************************/
mas01mc@742 11 #include <math.h>
mas01mc@742 12
mas01mc@742 13 #ifndef M_PIl
mas01mc@742 14 /** The constant Pi in high precision */
mas01mc@742 15 #define M_PIl 3.1415926535897932384626433832795029L
mas01mc@742 16 #endif
mas01mc@742 17 #ifndef M_GAMMAl
mas01mc@742 18 /** Euler's constant in high precision */
mas01mc@742 19 #define M_GAMMAl 0.5772156649015328606065120900824024L
mas01mc@742 20 #endif
mas01mc@742 21 #ifndef M_LN2l
mas01mc@742 22 /** the natural logarithm of 2 in high precision */
mas01mc@742 23 #define M_LN2l 0.6931471805599453094172321214581766L
mas01mc@742 24 #endif
mas01mc@742 25
mas01mc@742 26 /** The digamma function in long double precision.
mas01mc@742 27 * @param x the real value of the argument
mas01mc@742 28 * @return the value of the digamma (psi) function at that point
mas01mc@742 29 * @author Richard J. Mathar
mas01mc@742 30 * @since 2005-11-24
mas01mc@742 31 */
mas01mc@742 32 long double digammal(long double x)
mas01mc@742 33 {
mas01mc@742 34 /* force into the interval 1..3 */
mas01mc@742 35 if( x < 0.0L )
mas01mc@742 36 return digammal(1.0L-x)+M_PIl/tanl(M_PIl*(1.0L-x)) ; /* reflection formula */
mas01mc@742 37 else if( x < 1.0L )
mas01mc@742 38 return digammal(1.0L+x)-1.0L/x ;
mas01mc@742 39 else if ( x == 1.0L)
mas01mc@742 40 return -M_GAMMAl ;
mas01mc@742 41 else if ( x == 2.0L)
mas01mc@742 42 return 1.0L-M_GAMMAl ;
mas01mc@742 43 else if ( x == 3.0L)
mas01mc@742 44 return 1.5L-M_GAMMAl ;
mas01mc@742 45 else if ( x > 3.0L)
mas01mc@742 46 /* duplication formula */
mas01mc@742 47 return 0.5L*(digammal(x/2.0L)+digammal((x+1.0L)/2.0L))+M_LN2l ;
mas01mc@742 48 else
mas01mc@742 49 {
mas01mc@742 50 /* Just for your information, the following lines contain
mas01mc@742 51 * the Maple source code to re-generate the table that is
mas01mc@742 52 * eventually becoming the Kncoe[] array below
mas01mc@742 53 * interface(prettyprint=0) :
mas01mc@742 54 * Digits := 63 :
mas01mc@742 55 * r := 0 :
mas01mc@742 56 *
mas01mc@742 57 * for l from 1 to 60 do
mas01mc@742 58 * d := binomial(-1/2,l) :
mas01mc@742 59 * r := r+d*(-1)^l*(Zeta(2*l+1) -1) ;
mas01mc@742 60 * evalf(r) ;
mas01mc@742 61 * print(%,evalf(1+Psi(1)-r)) ;
mas01mc@742 62 *o d :
mas01mc@742 63 *
mas01mc@742 64 * for N from 1 to 28 do
mas01mc@742 65 * r := 0 :
mas01mc@742 66 * n := N-1 :
mas01mc@742 67 *
mas01mc@742 68 * for l from iquo(n+3,2) to 70 do
mas01mc@742 69 * d := 0 :
mas01mc@742 70 * for s from 0 to n+1 do
mas01mc@742 71 * d := d+(-1)^s*binomial(n+1,s)*binomial((s-1)/2,l) :
mas01mc@742 72 * od :
mas01mc@742 73 * if 2*l-n > 1 then
mas01mc@742 74 * r := r+d*(-1)^l*(Zeta(2*l-n) -1) :
mas01mc@742 75 * fi :
mas01mc@742 76 * od :
mas01mc@742 77 * print(evalf((-1)^n*2*r)) ;
mas01mc@742 78 *od :
mas01mc@742 79 *quit :
mas01mc@742 80 */
mas01mc@742 81 static long double Kncoe[] = { .30459198558715155634315638246624251L,
mas01mc@742 82 .72037977439182833573548891941219706L, -.12454959243861367729528855995001087L,
mas01mc@742 83 .27769457331927827002810119567456810e-1L, -.67762371439822456447373550186163070e-2L,
mas01mc@742 84 .17238755142247705209823876688592170e-2L, -.44817699064252933515310345718960928e-3L,
mas01mc@742 85 .11793660000155572716272710617753373e-3L, -.31253894280980134452125172274246963e-4L,
mas01mc@742 86 .83173997012173283398932708991137488e-5L, -.22191427643780045431149221890172210e-5L,
mas01mc@742 87 .59302266729329346291029599913617915e-6L, -.15863051191470655433559920279603632e-6L,
mas01mc@742 88 .42459203983193603241777510648681429e-7L, -.11369129616951114238848106591780146e-7L,
mas01mc@742 89 .304502217295931698401459168423403510e-8L, -.81568455080753152802915013641723686e-9L,
mas01mc@742 90 .21852324749975455125936715817306383e-9L, -.58546491441689515680751900276454407e-10L,
mas01mc@742 91 .15686348450871204869813586459513648e-10L, -.42029496273143231373796179302482033e-11L,
mas01mc@742 92 .11261435719264907097227520956710754e-11L, -.30174353636860279765375177200637590e-12L,
mas01mc@742 93 .80850955256389526647406571868193768e-13L, -.21663779809421233144009565199997351e-13L,
mas01mc@742 94 .58047634271339391495076374966835526e-14L, -.15553767189204733561108869588173845e-14L,
mas01mc@742 95 .41676108598040807753707828039353330e-15L, -.11167065064221317094734023242188463e-15L } ;
mas01mc@742 96
mas01mc@742 97 register long double Tn_1 = 1.0L ; /* T_{n-1}(x), started at n=1 */
mas01mc@742 98 register long double Tn = x-2.0L ; /* T_{n}(x) , started at n=1 */
mas01mc@742 99 register long double resul = Kncoe[0] + Kncoe[1]*Tn ;
mas01mc@742 100 register int n;
mas01mc@742 101
mas01mc@742 102 x -= 2.0L ;
mas01mc@742 103
mas01mc@742 104 for(n = 2 ; n < sizeof(Kncoe)/sizeof(long double) ;n++)
mas01mc@742 105 {
mas01mc@742 106 const long double Tn1 = 2.0L * x * Tn - Tn_1 ; /* Chebyshev recursion, Eq. 22.7.4 Abramowitz-Stegun */
mas01mc@742 107 resul += Kncoe[n]*Tn1 ;
mas01mc@742 108 Tn_1 = Tn ;
mas01mc@742 109 Tn = Tn1 ;
mas01mc@742 110 }
mas01mc@742 111 return resul ;
mas01mc@742 112 }
mas01mc@742 113 }
mas01mc@742 114
mas01mc@742 115 /** The optional interface to CREASO's IDL is added if someone has defined
mas01mc@742 116 * the cpp macro export_IDL_REF, which typically has been done by including the
mas01mc@742 117 * files stdio.h and idl_export.h before this one here.
mas01mc@742 118 */
mas01mc@742 119 #ifdef export_IDL_REF
mas01mc@742 120 /** CALL_EXTERNAL interface.
mas01mc@742 121 * dg = CALL_EXTERNAL('digamma.so',X)
mas01mc@742 122 * @pararm argc the number of arguments. This is supposed to be 1 and not
mas01mc@742 123 * checked further because it might have negative impact on performance.
mas01mc@742 124 * @pararm argv the parameter list. The first element is the parameter x
mas01mc@742 125 * supposed to be of type DOUBLE in IDL
mas01mc@742 126 * @return the return value, again of IDL-type DOUBLE
mas01mc@742 127 * @since 2007-01-16
mas01mc@742 128 * @author Richard J. Mathar
mas01mc@742 129 */
mas01mc@742 130 double digammal_idl(int argc, void *argv[])
mas01mc@742 131 {
mas01mc@742 132 long double x = *(double*)argv[0] ;
mas01mc@742 133 return (double)digammal(x) ;
mas01mc@742 134 }
mas01mc@742 135 #endif /* export_IDL_REF */
mas01mc@742 136
mas01mc@742 137
mas01mc@742 138 #ifdef MAIN
mas01mc@742 139
mas01mc@742 140 #include <stdlib.h>
mas01mc@742 141 #include <stdio.h>
mas01mc@742 142
mas01mc@742 143 int main(int argc, char **argv){
mas01mc@742 144 if (argc < 2){
mas01mc@742 145 fprintf(stderr, "Syntax: %s x\n", argv[0]);
mas01mc@742 146 exit(1);
mas01mc@742 147 }
mas01mc@742 148 double x = atof(argv[1]);
mas01mc@742 149 double y = digammal(x);
mas01mc@742 150 printf("%g\n", y);
mas01mc@742 151 return 0;
mas01mc@742 152 }
mas01mc@742 153 #endif /* MAIN */
mas01mc@742 154
mas01mc@742 155 #ifdef TEST
mas01mc@742 156
mas01mc@742 157 /* an alternate implementation for test purposes, using formula 6.3.16 of Abramowitz/Stegun with the
mas01mc@742 158 first n terms */
mas01mc@742 159 #include <stdio.h>
mas01mc@742 160
mas01mc@742 161 long double digammalAlt(long double x, int n)
mas01mc@742 162 {
mas01mc@742 163 /* force into the interval 1..3 */
mas01mc@742 164 if( x < 0.0L )
mas01mc@742 165 return digammalAlt(1.0L-x,n)+M_PIl/tanl(M_PIl*(1.0L-x)) ; /* reflection formula */
mas01mc@742 166 else if( x < 1.0L )
mas01mc@742 167 return digammalAlt(1.0L+x,n)-1.0L/x ;
mas01mc@742 168 else if ( x == 1.0L)
mas01mc@742 169 return -M_GAMMAl ;
mas01mc@742 170 else if ( x == 2.0L)
mas01mc@742 171 return 1.0L-M_GAMMAl ;
mas01mc@742 172 else if ( x == 3.0L)
mas01mc@742 173 return 1.5L-M_GAMMAl ;
mas01mc@742 174 else if ( x > 3.0L)
mas01mc@742 175 return digammalAlt(x-1.0L,n)+1.0L/(x-1.0L) ;
mas01mc@742 176 else
mas01mc@742 177 {
mas01mc@742 178 x -= 1.0L ;
mas01mc@742 179 register long double resul = -M_GAMMAl ;
mas01mc@742 180
mas01mc@742 181 for( ; n >= 1 ;n--)
mas01mc@742 182 resul += x/(n*(n+x)) ;
mas01mc@742 183 return resul ;
mas01mc@742 184 }
mas01mc@742 185 }
mas01mc@742 186 int main(int argc, char *argv[])
mas01mc@742 187 {
mas01mc@742 188 long double x;
mas01mc@742 189 for(x=0.01 ; x < 5. ; x += 0.02)
mas01mc@742 190 printf("%.2Lf %.30Lf %.30Lf %.30Lf\n",x, digammal(x), digammalAlt(x,100), digammalAlt(x,200) ) ;
mas01mc@742 191 }
mas01mc@742 192
mas01mc@742 193 #endif /* TEST */