gammaf.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /* gammaf.c
  2. *
  3. * Gamma function
  4. *
  5. *
  6. *
  7. * SYNOPSIS:
  8. *
  9. * float x, y, gammaf();
  10. * extern int sgngamf;
  11. *
  12. * y = gammaf( x );
  13. *
  14. *
  15. *
  16. * DESCRIPTION:
  17. *
  18. * Returns gamma function of the argument. The result is
  19. * correctly signed, and the sign (+1 or -1) is also
  20. * returned in a global (extern) variable named sgngamf.
  21. * This same variable is also filled in by the logarithmic
  22. * gamma function lgam().
  23. *
  24. * Arguments between 0 and 10 are reduced by recurrence and the
  25. * function is approximated by a polynomial function covering
  26. * the interval (2,3). Large arguments are handled by Stirling's
  27. * formula. Negative arguments are made positive using
  28. * a reflection formula.
  29. *
  30. *
  31. * ACCURACY:
  32. *
  33. * Relative error:
  34. * arithmetic domain # trials peak rms
  35. * IEEE 0,-33 100,000 5.7e-7 1.0e-7
  36. * IEEE -33,0 100,000 6.1e-7 1.2e-7
  37. *
  38. *
  39. */
  40. /* lgamf()
  41. *
  42. * Natural logarithm of gamma function
  43. *
  44. *
  45. *
  46. * SYNOPSIS:
  47. *
  48. * float x, y, lgamf();
  49. * extern int sgngamf;
  50. *
  51. * y = lgamf( x );
  52. *
  53. *
  54. *
  55. * DESCRIPTION:
  56. *
  57. * Returns the base e (2.718...) logarithm of the absolute
  58. * value of the gamma function of the argument.
  59. * The sign (+1 or -1) of the gamma function is returned in a
  60. * global (extern) variable named sgngamf.
  61. *
  62. * For arguments greater than 6.5, the logarithm of the gamma
  63. * function is approximated by the logarithmic version of
  64. * Stirling's formula. Arguments between 0 and +6.5 are reduced by
  65. * by recurrence to the interval [.75,1.25] or [1.5,2.5] of a rational
  66. * approximation. The cosecant reflection formula is employed for
  67. * arguments less than zero.
  68. *
  69. * Arguments greater than MAXLGM = 2.035093e36 return MAXNUM and an
  70. * error message.
  71. *
  72. *
  73. *
  74. * ACCURACY:
  75. *
  76. *
  77. *
  78. * arithmetic domain # trials peak rms
  79. * IEEE -100,+100 500,000 7.4e-7 6.8e-8
  80. * The error criterion was relative when the function magnitude
  81. * was greater than one but absolute when it was less than one.
  82. * The routine has low relative error for positive arguments.
  83. *
  84. * The following test used the relative error criterion.
  85. * IEEE -2, +3 100000 4.0e-7 5.6e-8
  86. *
  87. */
  88. /* gamma.c */
  89. /* gamma function */
  90. /*
  91. Cephes Math Library Release 2.7: July, 1998
  92. Copyright 1984, 1987, 1989, 1992, 1998 by Stephen L. Moshier
  93. */
  94. #include <math.h>
  95. /* define MAXGAM 34.84425627277176174 */
  96. /* Stirling's formula for the gamma function
  97. * gamma(x) = sqrt(2 pi) x^(x-.5) exp(-x) ( 1 + 1/x P(1/x) )
  98. * .028 < 1/x < .1
  99. * relative error < 1.9e-11
  100. */
  101. static float STIR[] = {
  102. -2.705194986674176E-003,
  103. 3.473255786154910E-003,
  104. 8.333331788340907E-002,
  105. };
  106. static float MAXSTIR = 26.77;
  107. static float SQTPIF = 2.50662827463100050242; /* sqrt( 2 pi ) */
  108. int sgngamf = 0;
  109. extern int sgngamf;
  110. extern float MAXLOGF, MAXNUMF, PIF;
  111. #ifdef ANSIC
  112. float expf(float);
  113. float logf(float);
  114. float powf( float, float );
  115. float sinf(float);
  116. float gammaf(float);
  117. float floorf(float);
  118. static float stirf(float);
  119. float polevlf( float, float *, int );
  120. float p1evlf( float, float *, int );
  121. #else
  122. float expf(), logf(), powf(), sinf(), floorf();
  123. float polevlf(), p1evlf();
  124. static float stirf();
  125. #endif
  126. /* Gamma function computed by Stirling's formula,
  127. * sqrt(2 pi) x^(x-.5) exp(-x) (1 + 1/x P(1/x))
  128. * The polynomial STIR is valid for 33 <= x <= 172.
  129. */
  130. static float stirf( float xx )
  131. {
  132. float x, y, w, v;
  133. x = xx;
  134. w = 1.0/x;
  135. w = 1.0 + w * polevlf( w, STIR, 2 );
  136. y = expf( -x );
  137. if( x > MAXSTIR )
  138. { /* Avoid overflow in pow() */
  139. v = powf( x, 0.5 * x - 0.25 );
  140. y *= v;
  141. y *= v;
  142. }
  143. else
  144. {
  145. y = powf( x, x - 0.5 ) * y;
  146. }
  147. y = SQTPIF * y * w;
  148. return( y );
  149. }
  150. /* gamma(x+2), 0 < x < 1 */
  151. static float P[] = {
  152. 1.536830450601906E-003,
  153. 5.397581592950993E-003,
  154. 4.130370201859976E-003,
  155. 7.232307985516519E-002,
  156. 8.203960091619193E-002,
  157. 4.117857447645796E-001,
  158. 4.227867745131584E-001,
  159. 9.999999822945073E-001,
  160. };
  161. float gammaf( float xx )
  162. {
  163. float p, q, x, z, nz;
  164. int i, direction, negative;
  165. x = xx;
  166. sgngamf = 1;
  167. negative = 0;
  168. nz = 0.0;
  169. if( x < 0.0 )
  170. {
  171. negative = 1;
  172. q = -x;
  173. p = floorf(q);
  174. if( p == q )
  175. goto goverf;
  176. i = p;
  177. if( (i & 1) == 0 )
  178. sgngamf = -1;
  179. nz = q - p;
  180. if( nz > 0.5 )
  181. {
  182. p += 1.0;
  183. nz = q - p;
  184. }
  185. nz = q * sinf( PIF * nz );
  186. if( nz == 0.0 )
  187. {
  188. goverf:
  189. mtherr( "gamma", OVERFLOW );
  190. return( sgngamf * MAXNUMF);
  191. }
  192. if( nz < 0 )
  193. nz = -nz;
  194. x = q;
  195. }
  196. if( x >= 10.0 )
  197. {
  198. z = stirf(x);
  199. }
  200. if( x < 2.0 )
  201. direction = 1;
  202. else
  203. direction = 0;
  204. z = 1.0;
  205. while( x >= 3.0 )
  206. {
  207. x -= 1.0;
  208. z *= x;
  209. }
  210. /*
  211. while( x < 0.0 )
  212. {
  213. if( x > -1.E-4 )
  214. goto small;
  215. z *=x;
  216. x += 1.0;
  217. }
  218. */
  219. while( x < 2.0 )
  220. {
  221. if( x < 1.e-4 )
  222. goto small;
  223. z *=x;
  224. x += 1.0;
  225. }
  226. if( direction )
  227. z = 1.0/z;
  228. if( x == 2.0 )
  229. return(z);
  230. x -= 2.0;
  231. p = z * polevlf( x, P, 7 );
  232. gdone:
  233. if( negative )
  234. {
  235. p = sgngamf * PIF/(nz * p );
  236. }
  237. return(p);
  238. small:
  239. if( x == 0.0 )
  240. {
  241. mtherr( "gamma", SING );
  242. return( MAXNUMF );
  243. }
  244. else
  245. {
  246. p = z / ((1.0 + 0.5772156649015329 * x) * x);
  247. goto gdone;
  248. }
  249. }
  250. /* log gamma(x+2), -.5 < x < .5 */
  251. static float B[] = {
  252. 6.055172732649237E-004,
  253. -1.311620815545743E-003,
  254. 2.863437556468661E-003,
  255. -7.366775108654962E-003,
  256. 2.058355474821512E-002,
  257. -6.735323259371034E-002,
  258. 3.224669577325661E-001,
  259. 4.227843421859038E-001
  260. };
  261. /* log gamma(x+1), -.25 < x < .25 */
  262. static float C[] = {
  263. 1.369488127325832E-001,
  264. -1.590086327657347E-001,
  265. 1.692415923504637E-001,
  266. -2.067882815621965E-001,
  267. 2.705806208275915E-001,
  268. -4.006931650563372E-001,
  269. 8.224670749082976E-001,
  270. -5.772156501719101E-001
  271. };
  272. /* log( sqrt( 2*pi ) ) */
  273. static float LS2PI = 0.91893853320467274178;
  274. #define MAXLGM 2.035093e36
  275. static float PIINV = 0.318309886183790671538;
  276. /* Logarithm of gamma function */
  277. float lgamf( float xx )
  278. {
  279. float p, q, w, z, x;
  280. float nx, tx;
  281. int i, direction;
  282. sgngamf = 1;
  283. x = xx;
  284. if( x < 0.0 )
  285. {
  286. q = -x;
  287. w = lgamf(q); /* note this modifies sgngam! */
  288. p = floorf(q);
  289. if( p == q )
  290. goto loverf;
  291. i = p;
  292. if( (i & 1) == 0 )
  293. sgngamf = -1;
  294. else
  295. sgngamf = 1;
  296. z = q - p;
  297. if( z > 0.5 )
  298. {
  299. p += 1.0;
  300. z = p - q;
  301. }
  302. z = q * sinf( PIF * z );
  303. if( z == 0.0 )
  304. goto loverf;
  305. z = -logf( PIINV*z ) - w;
  306. return( z );
  307. }
  308. if( x < 6.5 )
  309. {
  310. direction = 0;
  311. z = 1.0;
  312. tx = x;
  313. nx = 0.0;
  314. if( x >= 1.5 )
  315. {
  316. while( tx > 2.5 )
  317. {
  318. nx -= 1.0;
  319. tx = x + nx;
  320. z *=tx;
  321. }
  322. x += nx - 2.0;
  323. iv1r5:
  324. p = x * polevlf( x, B, 7 );
  325. goto cont;
  326. }
  327. if( x >= 1.25 )
  328. {
  329. z *= x;
  330. x -= 1.0; /* x + 1 - 2 */
  331. direction = 1;
  332. goto iv1r5;
  333. }
  334. if( x >= 0.75 )
  335. {
  336. x -= 1.0;
  337. p = x * polevlf( x, C, 7 );
  338. q = 0.0;
  339. goto contz;
  340. }
  341. while( tx < 1.5 )
  342. {
  343. if( tx == 0.0 )
  344. goto loverf;
  345. z *=tx;
  346. nx += 1.0;
  347. tx = x + nx;
  348. }
  349. direction = 1;
  350. x += nx - 2.0;
  351. p = x * polevlf( x, B, 7 );
  352. cont:
  353. if( z < 0.0 )
  354. {
  355. sgngamf = -1;
  356. z = -z;
  357. }
  358. else
  359. {
  360. sgngamf = 1;
  361. }
  362. q = logf(z);
  363. if( direction )
  364. q = -q;
  365. contz:
  366. return( p + q );
  367. }
  368. if( x > MAXLGM )
  369. {
  370. loverf:
  371. mtherr( "lgamf", OVERFLOW );
  372. return( sgngamf * MAXNUMF );
  373. }
  374. /* Note, though an asymptotic formula could be used for x >= 3,
  375. * there is cancellation error in the following if x < 6.5. */
  376. q = LS2PI - x;
  377. q += ( x - 0.5 ) * logf(x);
  378. if( x <= 1.0e4 )
  379. {
  380. z = 1.0/x;
  381. p = z * z;
  382. q += (( 6.789774945028216E-004 * p
  383. - 2.769887652139868E-003 ) * p
  384. + 8.333316229807355E-002 ) * z;
  385. }
  386. return( q );
  387. }