source: sasmodels/sasmodels/models/lib/sas_gamma.c @ 217590b

core_shell_microgelscostrafo411magnetic_modelticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since 217590b was 217590b, checked in by Paul Kienzle <pkienzle@…>, 8 years ago

fractal, fractal_core_shell: support fractal_dim as low as 0.

  • Property mode set to 100644
File size: 2.5 KB
Line 
1/*
2The wrapper for gamma function from OpenCL and standard libraries
3The OpenCL gamma function fails miserably on values lower than 1.0
4while works fine on larger values.
5We use gamma definition Gamma(t + 1) = t * Gamma(t) to compute
6to function for values lower than 1.0. Namely Gamma(t) = 1/t * Gamma(t + 1)
7*/
8
9#if defined(NEED_TGAMMA)
10static double cephes_stirf(double x)
11{
12        const double MAXSTIR=143.01608;
13        const double SQTPI=2.50662827463100050242E0;
14        double y, w, v;
15
16        w = 1.0 / x;
17
18        w = ((((
19                7.87311395793093628397E-4*w
20                - 2.29549961613378126380E-4)*w
21                - 2.68132617805781232825E-3)*w
22                + 3.47222221605458667310E-3)*w
23                + 8.33333333333482257126E-2)*w
24                + 1.0;
25        y = exp(x);
26        if (x > MAXSTIR)
27        { /* Avoid overflow in pow() */
28                v = pow(x, 0.5 * x - 0.25);
29                y = v * (v / y);
30        }
31        else
32        {
33                y = pow(x, x - 0.5) / y;
34        }
35        y = SQTPI * y * w;
36        return(y);
37}
38
39static double tgamma(double x) {
40        double p, q, z;
41        int sgngam;
42        int i;
43
44        sgngam = 1;
45        if (isnan(x))
46                return(x);
47        q = fabs(x);
48
49        if (q > 33.0)
50        {
51                if (x < 0.0)
52                {
53                        p = floor(q);
54                        if (p == q)
55                        {
56                                return (NAN);
57                        }
58                        i = p;
59                        if ((i & 1) == 0)
60                                sgngam = -1;
61                        z = q - p;
62                        if (z > 0.5)
63                        {
64                                p += 1.0;
65                                z = q - p;
66                        }
67                        z = q * sin(M_PI * z);
68                        if (z == 0.0)
69                        {
70                                return(NAN);
71                        }
72                        z = fabs(z);
73                        z = M_PI / (z * cephes_stirf(q));
74                }
75                else
76                {
77                        z = cephes_stirf(x);
78                }
79                return(sgngam * z);
80        }
81
82        z = 1.0;
83        while (x >= 3.0)
84        {
85                x -= 1.0;
86                z *= x;
87        }
88
89        while (x < 0.0)
90        {
91                if (x > -1.E-9)
92                        goto small;
93                z /= x;
94                x += 1.0;
95        }
96
97        while (x < 2.0)
98        {
99                if (x < 1.e-9)
100                        goto small;
101                z /= x;
102                x += 1.0;
103        }
104
105        if (x == 2.0)
106                return(z);
107
108        x -= 2.0;
109        p = (((((
110                +1.60119522476751861407E-4*x
111                + 1.19135147006586384913E-3)*x
112                + 1.04213797561761569935E-2)*x
113                + 4.76367800457137231464E-2)*x
114                + 2.07448227648435975150E-1)*x
115                + 4.94214826801497100753E-1)*x
116                + 9.99999999999999996796E-1;
117        q = ((((((
118                -2.31581873324120129819E-5*x
119                + 5.39605580493303397842E-4)*x
120                - 4.45641913851797240494E-3)*x
121                + 1.18139785222060435552E-2)*x
122                + 3.58236398605498653373E-2)*x
123                - 2.34591795718243348568E-1)*x
124                + 7.14304917030273074085E-2)*x
125                + 1.00000000000000000320E0;
126        return(z * p / q);
127
128small:
129        if (x == 0.0)
130        {
131                return (NAN);
132        }
133        else
134                return(z / ((1.0 + 0.5772156649015329 * x) * x));
135}
136#endif // NEED_TGAMMA
137
138
139inline double sas_gamma(double x) {
140#if 1
141    // Fast reliable gamma in [-n,171], where n is a small integer
142    double norm = 1.;
143    while (x < 1.) {
144        norm *= x;
145        x += 1.0;
146    }
147    return tgamma(x)/norm;
148#else
149    // Fast reliable gamma in [0,170]
150    return tgamma(x+1)/x;
151#endif
152}
Note: See TracBrowser for help on using the repository browser.