rgamma.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /* rgamma.c
  2. *
  3. * Reciprocal gamma function
  4. *
  5. *
  6. *
  7. * SYNOPSIS:
  8. *
  9. * double x, y, rgamma();
  10. *
  11. * y = rgamma( x );
  12. *
  13. *
  14. *
  15. * DESCRIPTION:
  16. *
  17. * Returns one divided by the gamma function of the argument.
  18. *
  19. * The function is approximated by a Chebyshev expansion in
  20. * the interval [0,1]. Range reduction is by recurrence
  21. * for arguments between -34.034 and +34.84425627277176174.
  22. * 1/MAXNUM is returned for positive arguments outside this
  23. * range. For arguments less than -34.034 the cosecant
  24. * reflection formula is applied; lograrithms are employed
  25. * to avoid unnecessary overflow.
  26. *
  27. * The reciprocal gamma function has no singularities,
  28. * but overflow and underflow may occur for large arguments.
  29. * These conditions return either MAXNUM or 1/MAXNUM with
  30. * appropriate sign.
  31. *
  32. * ACCURACY:
  33. *
  34. * Relative error:
  35. * arithmetic domain # trials peak rms
  36. * DEC -30,+30 4000 1.2e-16 1.8e-17
  37. * IEEE -30,+30 30000 1.1e-15 2.0e-16
  38. * For arguments less than -34.034 the peak error is on the
  39. * order of 5e-15 (DEC), excepting overflow or underflow.
  40. */
  41. /*
  42. Cephes Math Library Release 2.8: June, 2000
  43. Copyright 1985, 1987, 2000 by Stephen L. Moshier
  44. */
  45. #include <math.h>
  46. /* Chebyshev coefficients for reciprocal gamma function
  47. * in interval 0 to 1. Function is 1/(x gamma(x)) - 1
  48. */
  49. #ifdef UNK
  50. static double R[] = {
  51. 3.13173458231230000000E-17,
  52. -6.70718606477908000000E-16,
  53. 2.20039078172259550000E-15,
  54. 2.47691630348254132600E-13,
  55. -6.60074100411295197440E-12,
  56. 5.13850186324226978840E-11,
  57. 1.08965386454418662084E-9,
  58. -3.33964630686836942556E-8,
  59. 2.68975996440595483619E-7,
  60. 2.96001177518801696639E-6,
  61. -8.04814124978471142852E-5,
  62. 4.16609138709688864714E-4,
  63. 5.06579864028608725080E-3,
  64. -6.41925436109158228810E-2,
  65. -4.98558728684003594785E-3,
  66. 1.27546015610523951063E-1
  67. };
  68. #endif
  69. #ifdef DEC
  70. static unsigned short R[] = {
  71. 0022420,0066376,0176751,0071636,
  72. 0123501,0051114,0042104,0131153,
  73. 0024036,0107013,0126504,0033361,
  74. 0025613,0070040,0035174,0162316,
  75. 0126750,0037060,0077775,0122202,
  76. 0027541,0177143,0037675,0105150,
  77. 0030625,0141311,0075005,0115436,
  78. 0132017,0067714,0125033,0014721,
  79. 0032620,0063707,0105256,0152643,
  80. 0033506,0122235,0072757,0170053,
  81. 0134650,0144041,0015617,0016143,
  82. 0035332,0066125,0000776,0006215,
  83. 0036245,0177377,0137173,0131432,
  84. 0137203,0073541,0055645,0141150,
  85. 0136243,0057043,0026226,0017362,
  86. 0037402,0115554,0033441,0012310
  87. };
  88. #endif
  89. #ifdef IBMPC
  90. static unsigned short R[] = {
  91. 0x2e74,0xdfbd,0x0d9f,0x3c82,
  92. 0x964d,0x8888,0x2a49,0xbcc8,
  93. 0x86de,0x75a8,0xd1c1,0x3ce3,
  94. 0x9c9a,0x074f,0x6e04,0x3d51,
  95. 0xb490,0x0fff,0x07c6,0xbd9d,
  96. 0xb14d,0x67f7,0x3fcc,0x3dcc,
  97. 0xb364,0x2f40,0xb859,0x3e12,
  98. 0x633a,0x9543,0xedf9,0xbe61,
  99. 0xdab4,0xf155,0x0cf8,0x3e92,
  100. 0xfe05,0xaebd,0xd493,0x3ec8,
  101. 0xe38c,0x2371,0x1904,0xbf15,
  102. 0xc192,0xa03f,0x4d8a,0x3f3b,
  103. 0x7663,0xf7cf,0xbfdf,0x3f74,
  104. 0xb84d,0x2b74,0x6eec,0xbfb0,
  105. 0xc3de,0x6592,0x6bc4,0xbf74,
  106. 0x2299,0x86e4,0x536d,0x3fc0
  107. };
  108. #endif
  109. #ifdef MIEEE
  110. static unsigned short R[] = {
  111. 0x3c82,0x0d9f,0xdfbd,0x2e74,
  112. 0xbcc8,0x2a49,0x8888,0x964d,
  113. 0x3ce3,0xd1c1,0x75a8,0x86de,
  114. 0x3d51,0x6e04,0x074f,0x9c9a,
  115. 0xbd9d,0x07c6,0x0fff,0xb490,
  116. 0x3dcc,0x3fcc,0x67f7,0xb14d,
  117. 0x3e12,0xb859,0x2f40,0xb364,
  118. 0xbe61,0xedf9,0x9543,0x633a,
  119. 0x3e92,0x0cf8,0xf155,0xdab4,
  120. 0x3ec8,0xd493,0xaebd,0xfe05,
  121. 0xbf15,0x1904,0x2371,0xe38c,
  122. 0x3f3b,0x4d8a,0xa03f,0xc192,
  123. 0x3f74,0xbfdf,0xf7cf,0x7663,
  124. 0xbfb0,0x6eec,0x2b74,0xb84d,
  125. 0xbf74,0x6bc4,0x6592,0xc3de,
  126. 0x3fc0,0x536d,0x86e4,0x2299
  127. };
  128. #endif
  129. static char name[] = "rgamma";
  130. #ifdef ANSIPROT
  131. extern double chbevl ( double, void *, int );
  132. extern double exp ( double );
  133. extern double log ( double );
  134. extern double sin ( double );
  135. extern double lgam ( double );
  136. #else
  137. double chbevl(), exp(), log(), sin(), lgam();
  138. #endif
  139. extern double PI, MAXLOG, MAXNUM;
  140. double rgamma(x)
  141. double x;
  142. {
  143. double w, y, z;
  144. int sign;
  145. if( x > 34.84425627277176174)
  146. {
  147. mtherr( name, UNDERFLOW );
  148. return(1.0/MAXNUM);
  149. }
  150. if( x < -34.034 )
  151. {
  152. w = -x;
  153. z = sin( PI*w );
  154. if( z == 0.0 )
  155. return(0.0);
  156. if( z < 0.0 )
  157. {
  158. sign = 1;
  159. z = -z;
  160. }
  161. else
  162. sign = -1;
  163. y = log( w * z ) - log(PI) + lgam(w);
  164. if( y < -MAXLOG )
  165. {
  166. mtherr( name, UNDERFLOW );
  167. return( sign * 1.0 / MAXNUM );
  168. }
  169. if( y > MAXLOG )
  170. {
  171. mtherr( name, OVERFLOW );
  172. return( sign * MAXNUM );
  173. }
  174. return( sign * exp(y));
  175. }
  176. z = 1.0;
  177. w = x;
  178. while( w > 1.0 ) /* Downward recurrence */
  179. {
  180. w -= 1.0;
  181. z *= w;
  182. }
  183. while( w < 0.0 ) /* Upward recurrence */
  184. {
  185. z /= w;
  186. w += 1.0;
  187. }
  188. if( w == 0.0 ) /* Nonpositive integer */
  189. return(0.0);
  190. if( w == 1.0 ) /* Other integer */
  191. return( 1.0/z );
  192. y = w * ( 1.0 + chbevl( 4.0*w-2.0, R, 16 ) ) / z;
  193. return(y);
  194. }