Beispiel #1
0
        /// <summary>
        /// Calculates the specified Gamma function when <paramref name="a"/> is a half integer
        /// </summary>
        /// <param name="r"></param>
        /// <param name="a"></param>
        /// <param name="x"></param>
        /// <returns></returns>
        static double HalfIntegerA(Routine r, double a, double x)
        {
            Debug.Assert(a - Math.Floor(a) == 0.5);

            double sum = 0;

            if (a > 1)
            {
                sum = 1.0;
                double term = 1.0;
                for (int n = 2; n < a; ++n)
                {
                    term *= x / (n - 0.5);
                    sum  += term;
                }
            }

            double result;
            double mult = 2.0 * Constants.RecipSqrtPI * Math.Sqrt(x);

            if (r == Routine.Q || r == Routine.Upper)
            {
                result = Math2.Erfc(Math.Sqrt(x)) + sum * mult * Math.Exp(-x);
                return((r == Routine.Q) ? result : result *Math2.Tgamma(a));
            }
            else
            {
                result = Math2.Erf(Math.Sqrt(x)) - sum * mult * Math.Exp(-x);
                return((r == Routine.P) ? result : result *Math2.Tgamma(a));
            }
        }
Beispiel #2
0
        public static double TgammaLowerImp(double a, double x)
        {
            const Routine routine = Routine.Lower;

            // special values
            if (x == 0.0)
            {
                return(0.0);
            }
            if (double.IsInfinity(x))
            {
                return(Math2.Tgamma(a));
            }

            if (a == 1.0)
            {
                return(-Math2.Expm1(-x)); // 1.0 - Math.Exp(-x);
            }
            if (a == 0.5)
            {
                return(Constants.SqrtPI * Math2.Erf(Math.Sqrt(x)));
            }

            // Process small a, large x with asymptotic series, which is faster than CF
            if (x >= Asym_MinLargeZ(a))
            {
                return(Math2.Tgamma(a) - Asym_SeriesLargeZ(a, x) * Prefix(a, x) / x);
            }

            // is a small
            if ((a < 30) && (x >= a + 1) && (x < DoubleLimits.MaxLogValue))
            {
                double frac = a - Math.Floor(a);
                if (frac == 0)
                {
                    return(IntegerA(routine, a, x));
                }
                else if (frac == 0.5)
                {
                    return(HalfIntegerA(routine, a, x));
                }
            }

            if (x < (a + 1))
            {
                if (a < 1)
                {
                    return(SmallA(routine, a, x));
                }
                return(Prefix(a, x, 1 / a) * LowerSeries(a, x));
            }

            // Use CF for x > a+1
            return(TgammaMinusUpperFraction(a, x));
        }
Beispiel #3
0
        public static double GammaPImp(double a, double x)
        {
            const Routine routine = Routine.P;

            // special values
            if (x == 0.0)
            {
                return(0.0);
            }
            if (double.IsInfinity(x))
            {
                return(1.0);
            }

            if (a == 0)
            {
                return(1);
            }
            if (a == 1.0)
            {
                return(-Math2.Expm1(-x)); // 1.0 - Math.Exp(-x)
            }
            if (a == 0.5)
            {
                return(Math2.Erf(Math.Sqrt(x)));
            }

            // Process small a, large x with asymptotic series, which is faster than CF
            if (x >= Asym_MinLargeZ(a))
            {
                return(1 - Asym_SeriesLargeZ(a, x) * PrefixRegularized(a, x) / x);
            }

            // is a small
            if ((a < 30) && (x >= a + 1) && (x < DoubleLimits.MaxLogValue))
            {
                double frac = a - Math.Floor(a);
                if (frac == 0)
                {
                    return(IntegerA(routine, a, x));
                }
                else if (frac == 0.5)
                {
                    return(HalfIntegerA(routine, a, x));
                }
            }

            //
            // Begin by testing whether we're in the "bad" zone
            // where the result will be near 0.5 and the usual
            // series and continued fractions are slow to converge:
            //
            if (a > 20)
            {
                // This second limit below is chosen so that we use Temme's expansion
                // only if the result would be larger than about 10^-6.
                // Below that the regular series and continued fractions
                // converge OK, and if we use Temme's method we get increasing
                // errors from the dominant erfc term as it's (inexact) argument
                // increases in magnitude.

                double sigma = Math.Abs((x - a) / a);
                if (sigma < 0.4 || (a > 200 && 20 / a > sigma * sigma))
                {
                    double t = TemmeSymmetricAsym.GammaP(a, x);
                    return((x >= a) ? 1 - t : t);
                }
            }

            if (x < (a + 1))
            {
                if (a < 1)
                {
                    return(SmallA(routine, a, x));
                }
                return(PrefixRegularized(a, x) * LowerSeries(a, x) / a);
            }

            // Use CF for x > a+1
            return(1.0 - PrefixRegularized(a, x) * UpperFraction(a, x));
        }