Esempio n. 1
0
        // R file: lgammacor.c
        private static double lgammacor(double x)
        {
            double tmp;

            /* For IEEE double precision DBL_EPSILON = 2^-52 = 2.220446049250313e-16 :
             *   xbig = 2 ^ 26.5
             *   xmax = DBL_MAX / 48 =  2^1020 / 3
             */

            int nalgm = 5;
            double
                xbig = 94906265.62425156,
                xmax = 3.745194030963158e306;

            if (x < 10)
            {
                // ML_ERR_return_NAN
                return(RVaria.R_NaN);
            }
            else if (x >= xmax)
            {
                // ML_ERROR(ME_UNDERFLOW, "lgammacor");
                /* allow to underflow below */
            }
            else if (x < xbig)
            {
                tmp = 10 / x;
                return(RVaria.chebyshev_eval(tmp * tmp * 2 - 1, algmcs, nalgm) / x);
            }
            return(1 / (x * 12));
        }
Esempio n. 2
0
        /* R file: gamma.c
         * name used in R: gammafn
         */
        public static double Gamma(double x)
        {
            int    i, n;
            double y;
            double sinpiy, value;


            const double
                xmin  = -170.5674972726612,
                xmax  = 171.61447887182298,
                xsml  = 2.2474362225598545e-308,
                dxrel = 1.490116119384765696e-8;
            const int
                ngam = 22;


            if (double.IsNaN(x))
            {
                return(x);
            }

            /* If the argument is exactly zero or a negative integer
             * then return NaN. */
            if (x == 0 || (x < 0 && x == Math.Round(x)))
            {
                // ML_ERROR(ME_DOMAIN, "gammafn");
                return(double.NaN);
            }

            y = Math.Abs(x);

            if (y <= 10)
            {
                /* Compute gamma(x) for -10 <= x <= 10
                 * Reduce the interval and find gamma(1 + y) for 0 <= y < 1
                 * first of all. */

                n = (int)x;
                if (x < 0)
                {
                    --n;
                }
                y = x - n;/* n = floor(x)  ==>	y in [ 0, 1 ) */
                --n;
                value = RVaria.chebyshev_eval(y * 2 - 1, gamcs, ngam) + .9375;
                if (n == 0)
                {
                    return(value);/* x = 1.dddd = 1+y */
                }
                if (n < 0)
                {
                    /* compute gamma(x) for -10 <= x < 1 */

                    /* exact 0 or "-n" checked already above */

                    /* The answer is less than half precision */
                    /* because x too near a negative integer. */
                    if ((x < -0.5) && (Math.Abs(x - (int)(x - 0.5) / x) < dxrel))
                    {
                        // ML_ERROR(ME_PRECISION, "gammafn");
                    }

                    /* The argument is so close to 0 that the result would overflow. */
                    if (y < xsml)
                    {
                        // ML_ERROR(ME_RANGE, "gammafn");
                        if (x > 0)
                        {
                            return(double.PositiveInfinity);
                        }
                        else
                        {
                            return(double.NegativeInfinity);
                        }
                    }

                    n = -n;

                    for (i = 0; i < n; i++)
                    {
                        value /= (x + i);
                    }
                    return(value);
                }
                else
                {
                    /* gamma(x) for 2 <= x <= 10 */

                    for (i = 1; i <= n; i++)
                    {
                        value *= (y + i);
                    }
                    return(value);
                }
            }
            else
            {
                /* gamma(x) for	 y = |x| > 10. */

                if (x > xmax)
                {                       /* Overflow */
                    // ML_ERROR(ME_RANGE, "gammafn");
                    return(double.PositiveInfinity);
                }

                if (x < xmin)
                {                       /* Underflow */
                    // ML_ERROR(ME_UNDERFLOW, "gammafn");
                    return(0.0);
                }

                if (y <= 50 && y == (int)y)
                { /* compute (n - 1)! */
                    value = 1.0;
                    for (i = 2; i < y; i++)
                    {
                        value *= i;
                    }
                }
                else
                { /* normal case */
                    value = Math.Exp((y - 0.5) * Math.Log(y) - y + RVaria.M_LN_SQRT_2PI +
                                     ((2 * y == (int)2 * y) ? StirlingError(y) : lgammacor(y)));
                }
                if (x > 0)
                {
                    return(value);
                }

                if (Math.Abs((x - (int)(x - 0.5)) / x) < dxrel)
                {
                    /* The answer is less than half precision because */
                    /* the argument is too near a negative integer. */

                    // ML_ERROR(ME_PRECISION, "gammafn");
                }

                sinpiy = RVaria.sinpi(y);
                if (sinpiy == 0)
                {               /* Negative integer arg - overflow */
                    // ML_ERROR(ME_RANGE, "gammafn");
                    return(double.PositiveInfinity);
                }

                return(-RVaria.M_PI / (y * sinpiy * value));
            }
        }