source: sasview/src/sas/models/c_extension/cephes/gamma.c @ 573e7034

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 573e7034 was 79492222, checked in by krzywon, 10 years ago

Changed the file and folder names to remove all SANS references.

  • Property mode set to 100644
File size: 13.7 KB
Line 
1/*                                                      gamma.c
2 *
3 *      Gamma function
4 *
5 *
6 *
7 * SYNOPSIS:
8 *
9 * double x, y, gamma();
10 * extern int sgngam;
11 *
12 * y = gamma( 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 sgngam.
21 * This variable is also filled in by the logarithmic gamma
22 * function lgam().
23 *
24 * Arguments |x| <= 34 are reduced by recurrence and the function
25 * approximated by a rational function of degree 6/7 in the
26 * interval (2,3).  Large arguments are handled by Stirling's
27 * formula. Large 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 *    DEC      -34, 34      10000       1.3e-16     2.5e-17
36 *    IEEE    -170,-33      20000       2.3e-15     3.3e-16
37 *    IEEE     -33,  33     20000       9.4e-16     2.2e-16
38 *    IEEE      33, 171.6   20000       2.3e-15     3.2e-16
39 *
40 * Error for arguments outside the test range will be larger
41 * owing to error amplification by the exponential function.
42 *
43 */
44/*                                                      lgam()
45 *
46 *      Natural logarithm of gamma function
47 *
48 *
49 *
50 * SYNOPSIS:
51 *
52 * double x, y, lgam();
53 * extern int sgngam;
54 *
55 * y = lgam( x );
56 *
57 *
58 *
59 * DESCRIPTION:
60 *
61 * Returns the base e (2.718...) logarithm of the absolute
62 * value of the gamma function of the argument.
63 * The sign (+1 or -1) of the gamma function is returned in a
64 * global (extern) variable named sgngam.
65 *
66 * For arguments greater than 13, the logarithm of the gamma
67 * function is approximated by the logarithmic version of
68 * Stirling's formula using a polynomial approximation of
69 * degree 4. Arguments between -33 and +33 are reduced by
70 * recurrence to the interval [2,3] of a rational approximation.
71 * The cosecant reflection formula is employed for arguments
72 * less than -33.
73 *
74 * Arguments greater than MAXLGM return MAXNUM and an error
75 * message.  MAXLGM = 2.035093e36 for DEC
76 * arithmetic or 2.556348e305 for IEEE arithmetic.
77 *
78 *
79 *
80 * ACCURACY:
81 *
82 *
83 * arithmetic      domain        # trials     peak         rms
84 *    DEC     0, 3                  7000     5.2e-17     1.3e-17
85 *    DEC     2.718, 2.035e36       5000     3.9e-17     9.9e-18
86 *    IEEE    0, 3                 28000     5.4e-16     1.1e-16
87 *    IEEE    2.718, 2.556e305     40000     3.5e-16     8.3e-17
88 * The error criterion was relative when the function magnitude
89 * was greater than one but absolute when it was less than one.
90 *
91 * The following test used the relative error criterion, though
92 * at certain points the relative error could be much higher than
93 * indicated.
94 *    IEEE    -200, -4             10000     4.8e-16     1.3e-16
95 *
96 */
97
98/*                                                      gamma.c */
99/*      gamma function  */
100
101/*
102Cephes Math Library Release 2.8:  June, 2000
103Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
104*/
105
106
107#include "mconf.h"
108
109#ifdef UNK
110static double P[] = {
111  1.60119522476751861407E-4,
112  1.19135147006586384913E-3,
113  1.04213797561761569935E-2,
114  4.76367800457137231464E-2,
115  2.07448227648435975150E-1,
116  4.94214826801497100753E-1,
117  9.99999999999999996796E-1
118};
119static double Q[] = {
120-2.31581873324120129819E-5,
121 5.39605580493303397842E-4,
122-4.45641913851797240494E-3,
123 1.18139785222060435552E-2,
124 3.58236398605498653373E-2,
125-2.34591795718243348568E-1,
126 7.14304917030273074085E-2,
127 1.00000000000000000320E0
128};
129#define MAXGAM 171.624376956302725
130static double LOGPI = 1.14472988584940017414;
131#endif
132
133#ifdef DEC
134static unsigned short P[] = {
1350035047,0162701,0146301,0005234,
1360035634,0023437,0032065,0176530,
1370036452,0137157,0047330,0122574,
1380037103,0017310,0143041,0017232,
1390037524,0066516,0162563,0164605,
1400037775,0004671,0146237,0014222,
1410040200,0000000,0000000,0000000
142};
143static unsigned short Q[] = {
1440134302,0041724,0020006,0116565,
1450035415,0072121,0044251,0025634,
1460136222,0003447,0035205,0121114,
1470036501,0107552,0154335,0104271,
1480037022,0135717,0014776,0171471,
1490137560,0034324,0165024,0037021,
1500037222,0045046,0047151,0161213,
1510040200,0000000,0000000,0000000
152};
153#define MAXGAM 34.84425627277176174
154static unsigned short LPI[4] = {
1550040222,0103202,0043475,0006750,
156};
157#define LOGPI *(double *)LPI
158#endif
159
160#ifdef IBMPC
161static unsigned short P[] = {
1620x2153,0x3998,0xfcb8,0x3f24,
1630xbfab,0xe686,0x84e3,0x3f53,
1640x14b0,0xe9db,0x57cd,0x3f85,
1650x23d3,0x18c4,0x63d9,0x3fa8,
1660x7d31,0xdcae,0x8da9,0x3fca,
1670xe312,0x3993,0xa137,0x3fdf,
1680x0000,0x0000,0x0000,0x3ff0
169};
170static unsigned short Q[] = {
1710xd3af,0x8400,0x487a,0xbef8,
1720x2573,0x2915,0xae8a,0x3f41,
1730xb44a,0xe750,0x40e4,0xbf72,
1740xb117,0x5b1b,0x31ed,0x3f88,
1750xde67,0xe33f,0x5779,0x3fa2,
1760x87c2,0x9d42,0x071a,0xbfce,
1770x3c51,0xc9cd,0x4944,0x3fb2,
1780x0000,0x0000,0x0000,0x3ff0
179};
180#define MAXGAM 171.624376956302725
181static unsigned short LPI[4] = {
1820xa1bd,0x48e7,0x50d0,0x3ff2,
183};
184#define LOGPI *(double *)LPI
185#endif
186
187#ifdef MIEEE
188static unsigned short P[] = {
1890x3f24,0xfcb8,0x3998,0x2153,
1900x3f53,0x84e3,0xe686,0xbfab,
1910x3f85,0x57cd,0xe9db,0x14b0,
1920x3fa8,0x63d9,0x18c4,0x23d3,
1930x3fca,0x8da9,0xdcae,0x7d31,
1940x3fdf,0xa137,0x3993,0xe312,
1950x3ff0,0x0000,0x0000,0x0000
196};
197static unsigned short Q[] = {
1980xbef8,0x487a,0x8400,0xd3af,
1990x3f41,0xae8a,0x2915,0x2573,
2000xbf72,0x40e4,0xe750,0xb44a,
2010x3f88,0x31ed,0x5b1b,0xb117,
2020x3fa2,0x5779,0xe33f,0xde67,
2030xbfce,0x071a,0x9d42,0x87c2,
2040x3fb2,0x4944,0xc9cd,0x3c51,
2050x3ff0,0x0000,0x0000,0x0000
206};
207#define MAXGAM 171.624376956302725
208static unsigned short LPI[4] = {
2090x3ff2,0x50d0,0x48e7,0xa1bd,
210};
211#define LOGPI *(double *)LPI
212#endif
213
214/* Stirling's formula for the gamma function */
215#if UNK
216static double STIR[5] = {
217 7.87311395793093628397E-4,
218-2.29549961613378126380E-4,
219-2.68132617805781232825E-3,
220 3.47222221605458667310E-3,
221 8.33333333333482257126E-2,
222};
223#define MAXSTIR 143.01608
224static double SQTPI = 2.50662827463100050242E0;
225#endif
226#if DEC
227static unsigned short STIR[20] = {
2280035516,0061622,0144553,0112224,
2290135160,0131531,0037460,0165740,
2300136057,0134460,0037242,0077270,
2310036143,0107070,0156306,0027751,
2320037252,0125252,0125252,0146064,
233};
234#define MAXSTIR 26.77
235static unsigned short SQT[4] = {
2360040440,0066230,0177661,0034055,
237};
238#define SQTPI *(double *)SQT
239#endif
240#if IBMPC
241static unsigned short STIR[20] = {
2420x7293,0x592d,0xcc72,0x3f49,
2430x1d7c,0x27e6,0x166b,0xbf2e,
2440x4fd7,0x07d4,0xf726,0xbf65,
2450xc5fd,0x1b98,0x71c7,0x3f6c,
2460x5986,0x5555,0x5555,0x3fb5,
247};
248#define MAXSTIR 143.01608
249static unsigned short SQT[4] = {
2500x2706,0x1ff6,0x0d93,0x4004,
251};
252#define SQTPI *(double *)SQT
253#endif
254#if MIEEE
255static unsigned short STIR[20] = {
2560x3f49,0xcc72,0x592d,0x7293,
2570xbf2e,0x166b,0x27e6,0x1d7c,
2580xbf65,0xf726,0x07d4,0x4fd7,
2590x3f6c,0x71c7,0x1b98,0xc5fd,
2600x3fb5,0x5555,0x5555,0x5986,
261};
262#define MAXSTIR 143.01608
263static unsigned short SQT[4] = {
2640x4004,0x0d93,0x1ff6,0x2706,
265};
266#define SQTPI *(double *)SQT
267#endif
268
269int sgngam = 0;
270extern int sgngam;
271extern double MAXLOG, MAXNUM, PI;
272#ifdef ANSIPROT
273extern double pow ( double, double );
274extern double log ( double );
275extern double exp ( double );
276extern double sin ( double );
277extern double polevl ( double, void *, int );
278extern double p1evl ( double, void *, int );
279extern double floor ( double );
280extern double fabs ( double );
281extern int isnan ( double );
282extern int isfinite ( double );
283static double stirf ( double );
284double lgam ( double );
285#else
286double pow(), log(), exp(), sin(), polevl(), p1evl(), floor(), fabs();
287int isnan(), isfinite();
288static double stirf();
289double lgam();
290#endif
291#ifdef INFINITIES
292extern double INFINITY;
293#endif
294#ifdef NANS
295extern double NAN;
296#endif
297
298/* Gamma function computed by Stirling's formula.
299 * The polynomial STIR is valid for 33 <= x <= 172.
300 */
301static double stirf(x)
302double x;
303{
304double y, w, v;
305
306w = 1.0/x;
307w = 1.0 + w * polevl( w, STIR, 4 );
308y = exp(x);
309if( x > MAXSTIR )
310        { /* Avoid overflow in pow() */
311        v = pow( x, 0.5 * x - 0.25 );
312        y = v * (v / y);
313        }
314else
315        {
316        y = pow( x, x - 0.5 ) / y;
317        }
318y = SQTPI * y * w;
319return( y );
320}
321
322
323
324double gamma(x)
325double x;
326{
327double p, q, z;
328int i;
329
330sgngam = 1;
331#ifdef NANS
332if( isnan(x) )
333        return(x);
334#endif
335#ifdef INFINITIES
336#ifdef NANS
337if( x == INFINITY )
338        return(x);
339if( x == -INFINITY )
340        return(NAN);
341#else
342if( !isfinite(x) )
343        return(x);
344#endif
345#endif
346q = fabs(x);
347
348if( q > 33.0 )
349        {
350        if( x < 0.0 )
351                {
352                p = floor(q);
353                if( p == q )
354                        {
355#ifdef NANS
356gamnan:
357                        mtherr( "gamma", DOMAIN );
358                        return (NAN);
359#else
360                        goto goverf;
361#endif
362                        }
363                i = p;
364                if( (i & 1) == 0 )
365                        sgngam = -1;
366                z = q - p;
367                if( z > 0.5 )
368                        {
369                        p += 1.0;
370                        z = q - p;
371                        }
372                z = q * sin( PI * z );
373                if( z == 0.0 )
374                        {
375#ifdef INFINITIES
376                        return( sgngam * INFINITY);
377#else
378goverf:
379                        mtherr( "gamma", OVERFLOW );
380                        return( sgngam * MAXNUM);
381#endif
382                        }
383                z = fabs(z);
384                z = PI/(z * stirf(q) );
385                }
386        else
387                {
388                z = stirf(x);
389                }
390        return( sgngam * z );
391        }
392
393z = 1.0;
394while( x >= 3.0 )
395        {
396        x -= 1.0;
397        z *= x;
398        }
399
400while( x < 0.0 )
401        {
402        if( x > -1.E-9 )
403                goto small;
404        z /= x;
405        x += 1.0;
406        }
407
408while( x < 2.0 )
409        {
410        if( x < 1.e-9 )
411                goto small;
412        z /= x;
413        x += 1.0;
414        }
415
416if( x == 2.0 )
417        return(z);
418
419x -= 2.0;
420p = polevl( x, P, 6 );
421q = polevl( x, Q, 7 );
422return( z * p / q );
423
424small:
425if( x == 0.0 )
426        {
427#ifdef INFINITIES
428#ifdef NANS
429          goto gamnan;
430#else
431          return( INFINITY );
432#endif
433#else
434        mtherr( "gamma", SING );
435        return( MAXNUM );
436#endif
437        }
438else
439        return( z/((1.0 + 0.5772156649015329 * x) * x) );
440}
441
442
443
444/* A[]: Stirling's formula expansion of log gamma
445 * B[], C[]: log gamma function between 2 and 3
446 */
447#ifdef UNK
448static double A[] = {
449 8.11614167470508450300E-4,
450-5.95061904284301438324E-4,
451 7.93650340457716943945E-4,
452-2.77777777730099687205E-3,
453 8.33333333333331927722E-2
454};
455static double B[] = {
456-1.37825152569120859100E3,
457-3.88016315134637840924E4,
458-3.31612992738871184744E5,
459-1.16237097492762307383E6,
460-1.72173700820839662146E6,
461-8.53555664245765465627E5
462};
463static double C[] = {
464/* 1.00000000000000000000E0, */
465-3.51815701436523470549E2,
466-1.70642106651881159223E4,
467-2.20528590553854454839E5,
468-1.13933444367982507207E6,
469-2.53252307177582951285E6,
470-2.01889141433532773231E6
471};
472/* log( sqrt( 2*pi ) ) */
473static double LS2PI  =  0.91893853320467274178;
474#define MAXLGM 2.556348e305
475#endif
476
477#ifdef DEC
478static unsigned short A[] = {
4790035524,0141201,0034633,0031405,
4800135433,0176755,0126007,0045030,
4810035520,0006371,0003342,0172730,
4820136066,0005540,0132605,0026407,
4830037252,0125252,0125252,0125132
484};
485static unsigned short B[] = {
4860142654,0044014,0077633,0035410,
4870144027,0110641,0125335,0144760,
4880144641,0165637,0142204,0047447,
4890145215,0162027,0146246,0155211,
4900145322,0026110,0010317,0110130,
4910145120,0061472,0120300,0025363
492};
493static unsigned short C[] = {
494/*0040200,0000000,0000000,0000000*/
4950142257,0164150,0163630,0112622,
4960143605,0050153,0156116,0135272,
4970144527,0056045,0145642,0062332,
4980145213,0012063,0106250,0001025,
4990145432,0111254,0044577,0115142,
5000145366,0071133,0050217,0005122
501};
502/* log( sqrt( 2*pi ) ) */
503static unsigned short LS2P[] = {040153,037616,041445,0172645,};
504#define LS2PI *(double *)LS2P
505#define MAXLGM 2.035093e36
506#endif
507
508#ifdef IBMPC
509static unsigned short A[] = {
5100x6661,0x2733,0x9850,0x3f4a,
5110xe943,0xb580,0x7fbd,0xbf43,
5120x5ebb,0x20dc,0x019f,0x3f4a,
5130xa5a1,0x16b0,0xc16c,0xbf66,
5140x554b,0x5555,0x5555,0x3fb5
515};
516static unsigned short B[] = {
5170x6761,0x8ff3,0x8901,0xc095,
5180xb93e,0x355b,0xf234,0xc0e2,
5190x89e5,0xf890,0x3d73,0xc114,
5200xdb51,0xf994,0xbc82,0xc131,
5210xf20b,0x0219,0x4589,0xc13a,
5220x055e,0x5418,0x0c67,0xc12a
523};
524static unsigned short C[] = {
525/*0x0000,0x0000,0x0000,0x3ff0,*/
5260x12b2,0x1cf3,0xfd0d,0xc075,
5270xd757,0x7b89,0xaa0d,0xc0d0,
5280x4c9b,0xb974,0xeb84,0xc10a,
5290x0043,0x7195,0x6286,0xc131,
5300xf34c,0x892f,0x5255,0xc143,
5310xe14a,0x6a11,0xce4b,0xc13e
532};
533/* log( sqrt( 2*pi ) ) */
534static unsigned short LS2P[] = {
5350xbeb5,0xc864,0x67f1,0x3fed
536};
537#define LS2PI *(double *)LS2P
538#define MAXLGM 2.556348e305
539#endif
540
541#ifdef MIEEE
542static unsigned short A[] = {
5430x3f4a,0x9850,0x2733,0x6661,
5440xbf43,0x7fbd,0xb580,0xe943,
5450x3f4a,0x019f,0x20dc,0x5ebb,
5460xbf66,0xc16c,0x16b0,0xa5a1,
5470x3fb5,0x5555,0x5555,0x554b
548};
549static unsigned short B[] = {
5500xc095,0x8901,0x8ff3,0x6761,
5510xc0e2,0xf234,0x355b,0xb93e,
5520xc114,0x3d73,0xf890,0x89e5,
5530xc131,0xbc82,0xf994,0xdb51,
5540xc13a,0x4589,0x0219,0xf20b,
5550xc12a,0x0c67,0x5418,0x055e
556};
557static unsigned short C[] = {
5580xc075,0xfd0d,0x1cf3,0x12b2,
5590xc0d0,0xaa0d,0x7b89,0xd757,
5600xc10a,0xeb84,0xb974,0x4c9b,
5610xc131,0x6286,0x7195,0x0043,
5620xc143,0x5255,0x892f,0xf34c,
5630xc13e,0xce4b,0x6a11,0xe14a
564};
565/* log( sqrt( 2*pi ) ) */
566static unsigned short LS2P[] = {
5670x3fed,0x67f1,0xc864,0xbeb5
568};
569#define LS2PI *(double *)LS2P
570#define MAXLGM 2.556348e305
571#endif
572
573
574/* Logarithm of gamma function */
575
576
577double lgam(x)
578double x;
579{
580double p, q, u, w, z;
581int i;
582
583sgngam = 1;
584#ifdef NANS
585if( isnan(x) )
586        return(x);
587#endif
588
589#ifdef INFINITIES
590if( !isfinite(x) )
591        return(INFINITY);
592#endif
593
594if( x < -34.0 )
595        {
596        q = -x;
597        w = lgam(q); /* note this modifies sgngam! */
598        p = floor(q);
599        if( p == q )
600                {
601lgsing:
602#ifdef INFINITIES
603                mtherr( "lgam", SING );
604                return (INFINITY);
605#else
606                goto loverf;
607#endif
608                }
609        i = p;
610        if( (i & 1) == 0 )
611                sgngam = -1;
612        else
613                sgngam = 1;
614        z = q - p;
615        if( z > 0.5 )
616                {
617                p += 1.0;
618                z = p - q;
619                }
620        z = q * sin( PI * z );
621        if( z == 0.0 )
622                goto lgsing;
623/*      z = log(PI) - log( z ) - w;*/
624        z = LOGPI - log( z ) - w;
625        return( z );
626        }
627
628if( x < 13.0 )
629        {
630        z = 1.0;
631        p = 0.0;
632        u = x;
633        while( u >= 3.0 )
634                {
635                p -= 1.0;
636                u = x + p;
637                z *= u;
638                }
639        while( u < 2.0 )
640                {
641                if( u == 0.0 )
642                        goto lgsing;
643                z /= u;
644                p += 1.0;
645                u = x + p;
646                }
647        if( z < 0.0 )
648                {
649                sgngam = -1;
650                z = -z;
651                }
652        else
653                sgngam = 1;
654        if( u == 2.0 )
655                return( log(z) );
656        p -= 2.0;
657        x = x + p;
658        p = x * polevl( x, B, 5 ) / p1evl( x, C, 6);
659        return( log(z) + p );
660        }
661
662if( x > MAXLGM )
663        {
664#ifdef INFINITIES
665        return( sgngam * INFINITY );
666#else
667loverf:
668        mtherr( "lgam", OVERFLOW );
669        return( sgngam * MAXNUM );
670#endif
671        }
672
673q = ( x - 0.5 ) * log(x) - x + LS2PI;
674if( x > 1.0e8 )
675        return( q );
676
677p = 1.0/(x*x);
678if( x >= 1000.0 )
679        q += ((   7.9365079365079365079365e-4 * p
680                - 2.7777777777777777777778e-3) *p
681                + 0.0833333333333333333333) / x;
682else
683        q += polevl( p, A, 4 ) / x;
684return( q );
685}
Note: See TracBrowser for help on using the repository browser.