/**
         * Real valued log gamma function.
         * @param x
         * @return  Returns log value from gamma function.
         */
        public static double logGamma(double x)
        {
            if (Double.IsNaN(x))
            {
                return(Double.NaN);
            }
            if (Double.IsPositiveInfinity(x))
            {
                return(Double.PositiveInfinity);
            }
            if (Double.IsNegativeInfinity(x))
            {
                return(Double.NaN);
            }
            if (MathFunctions.isInteger(x))
            {
                if (x >= 0)
                {
                    return(MathFunctions.ln(Math.Abs(gammaInt((long)(Math.Round(x))))));
                }
                else
                {
                    return(MathFunctions.ln(Math.Abs(gammaInt(-(long)(Math.Round(-x))))));
                }
            }
            double p, q, w, z;

            if (x < -34.0)
            {
                q = -x;
                w = logGamma(q);
                p = Math.Floor(q);
                if (p == q)
                {
                    return(Double.NaN);
                }
                z = q - p;
                if (z > 0.5)
                {
                    p += 1.0;
                    z  = p - q;
                }
                z = q * Math.Sin(Math.PI * z);
                if (z == 0.0)
                {
                    return(Double.NaN);
                }
                z = MathConstants.LNPI - Math.Log(z) - w;
                return(z);
            }
            if (x < 13.0)
            {
                z = 1.0;
                while (x >= 3.0)
                {
                    x -= 1.0;
                    z *= x;
                }
                while (x < 2.0)
                {
                    if (x == 0.0)
                    {
                        return(Double.NaN);
                    }
                    z /= x;
                    x += 1.0;
                }
                if (z < 0.0)
                {
                    z = -z;
                }
                if (x == 2.0)
                {
                    return(Math.Log(z));
                }
                x -= 2.0;
                p  = x * Evaluate.polevl(x, Coefficients.logGammaB, 5) / Evaluate.p1evl(x, Coefficients.logGammaC, 6);
                return(Math.Log(z) + p);
            }
            if (x > 2.556348e305)
            {
                return(Double.NaN);
            }
            q = (x - 0.5) * Math.Log(x) - x + 0.91893853320467274178;
            if (x > 1.0e8)
            {
                return(q);
            }
            p = 1.0 / (x * x);
            if (x >= 1000.0)
            {
                q += ((7.9365079365079365079365e-4 * p - 2.7777777777777777777778e-3) * p + 0.0833333333333333333333) / x;
            }
            else
            {
                q += Evaluate.polevl(p, Coefficients.logGammaA, 4) / x;
            }
            return(q);
        }
        /**
         * Calculates the inverse error function evaluated at x.
         * @param x
         * @param invert
         * @return
         */
        private static double erfImp(double z, bool invert)
        {
            if (z < 0)
            {
                if (!invert)
                {
                    return(-erfImp(-z, false));
                }
                if (z < -0.5)
                {
                    return(2 - erfImp(-z, true));
                }
                return(1 + erfImp(-z, false));
            }
            double result;

            if (z < 0.5)
            {
                if (z < 1e-10)
                {
                    result = (z * 1.125) + (z * 0.003379167095512573896158903121545171688);
                }
                else
                {
                    result = (z * 1.125) + (z * Evaluate.polynomial(z, Coefficients.erfImpAn) / Evaluate.polynomial(z, Coefficients.erfImpAd));
                }
            }
            else if ((z < 110) || ((z < 110) && invert))
            {
                invert = !invert;
                double r, b;
                if (z < 0.75)
                {
                    r = Evaluate.polynomial(z - 0.5, Coefficients.erfImpBn) / Evaluate.polynomial(z - 0.5, Coefficients.erfImpBd);
                    b = 0.3440242112F;
                }
                else if (z < 1.25)
                {
                    r = Evaluate.polynomial(z - 0.75, Coefficients.erfImpCn) / Evaluate.polynomial(z - 0.75, Coefficients.erfImpCd);
                    b = 0.419990927F;
                }
                else if (z < 2.25)
                {
                    r = Evaluate.polynomial(z - 1.25, Coefficients.erfImpDn) / Evaluate.polynomial(z - 1.25, Coefficients.erfImpDd);
                    b = 0.4898625016F;
                }
                else if (z < 3.5)
                {
                    r = Evaluate.polynomial(z - 2.25, Coefficients.erfImpEn) / Evaluate.polynomial(z - 2.25, Coefficients.erfImpEd);
                    b = 0.5317370892F;
                }
                else if (z < 5.25)
                {
                    r = Evaluate.polynomial(z - 3.5, Coefficients.erfImpFn) / Evaluate.polynomial(z - 3.5, Coefficients.erfImpFd);
                    b = 0.5489973426F;
                }
                else if (z < 8)
                {
                    r = Evaluate.polynomial(z - 5.25, Coefficients.erfImpGn) / Evaluate.polynomial(z - 5.25, Coefficients.erfImpGd);
                    b = 0.5571740866F;
                }
                else if (z < 11.5)
                {
                    r = Evaluate.polynomial(z - 8, Coefficients.erfImpHn) / Evaluate.polynomial(z - 8, Coefficients.erfImpHd);
                    b = 0.5609807968F;
                }
                else if (z < 17)
                {
                    r = Evaluate.polynomial(z - 11.5, Coefficients.erfImpIn) / Evaluate.polynomial(z - 11.5, Coefficients.erfImpId);
                    b = 0.5626493692F;
                }
                else if (z < 24)
                {
                    r = Evaluate.polynomial(z - 17, Coefficients.erfImpJn) / Evaluate.polynomial(z - 17, Coefficients.erfImpJd);
                    b = 0.5634598136F;
                }
                else if (z < 38)
                {
                    r = Evaluate.polynomial(z - 24, Coefficients.erfImpKn) / Evaluate.polynomial(z - 24, Coefficients.erfImpKd);
                    b = 0.5638477802F;
                }
                else if (z < 60)
                {
                    r = Evaluate.polynomial(z - 38, Coefficients.erfImpLn) / Evaluate.polynomial(z - 38, Coefficients.erfImpLd);
                    b = 0.5640528202F;
                }
                else if (z < 85)
                {
                    r = Evaluate.polynomial(z - 60, Coefficients.erfImpMn) / Evaluate.polynomial(z - 60, Coefficients.erfImpMd);
                    b = 0.5641309023F;
                }
                else
                {
                    r = Evaluate.polynomial(z - 85, Coefficients.erfImpNn) / Evaluate.polynomial(z - 85, Coefficients.erfImpNd);
                    b = 0.5641584396F;
                }
                double g = MathFunctions.exp(-z * z) / z;
                result = (g * b) + (g * r);
            }
            else
            {
                result = 0;
                invert = !invert;
            }
            if (invert)
            {
                result = 1 - result;
            }
            return(result);
        }