Пример #1
0
        /// <summary>
        /// Returns the value "x" such that q == GammaQ(a, x);
        /// </summary>
        /// <param name="a">Requires a > 0</param>
        /// <param name="q">Requires 0 ≤ q ≤ 1</param>
        public static double GammaQInv(double a, double q)
        {
            if ((!(a > 0) || double.IsInfinity(a)) ||
                (!(q >= 0 && q <= 1)))
            {
                Policies.ReportDomainError("GammaQInv(a: {0}, q: {1}): Requires finite a > 0; q in [0,1]", a, q);
                return(double.NaN);
            }

            if (q == 0)
            {
                return(double.PositiveInfinity);
            }
            if (q == 1)
            {
                return(0);
            }

            // Q(1,x) = e^-x
            if (a == 1)
            {
                return(-Math.Log(q));
            }
            // Q(1/2, x) = erfc(sqrt(x))
            if (a == 0.5)
            {
                return(Squared(Math2.ErfcInv(q)));
            }


            double guess = _IgammaInv.GammaPInvGuess(a, 1 - q, q, out bool has10Digits);

            var(lower, upper) = _IgammaInv.GammaQInvLimits(a, q);

            // there can be some numerical uncertainties in the limits,
            // particularly for denormalized values, so adjust the limits
            if (upper == 0 && lower == 0)
            {
                return(0.0);
            }
            if (guess <= DoubleLimits.MinNormalValue)
            {
                return(guess);
            }
            if (guess <= lower)
            {
                lower = DoubleLimits.MinNormalValue;
            }
            if (guess > upper)
            {
                upper = guess;
            }


            return(_IgammaInv.SolveGivenAQ(a, q, guess, lower, upper));
        }
Пример #2
0
        static double InverseNegativeBinomialCornishFisher(double n, double sf, double sfc, double p, double q)
        {
            // mean:
            double m = n * (sfc) / sf;
            double t = Math.Sqrt(n * (sfc));
            // standard deviation:
            double sigma = t / sf;
            // skewness
            double sk = (1 + sfc) / t;
            // kurtosis:
            double k = (6 - sf * (5 + sfc)) / (n * (sfc));
            // Get the inverse of a std normal distribution:
            double x = Math2.ErfcInv(p > q ? 2 * q : 2 * p) * Constants.Sqrt2;

            // Set the sign:
            if (p < 0.5)
            {
                x = -x;
            }
            double x2 = x * x;
            // w is correction term due to skewness
            double w = x + sk * (x2 - 1) / 6;

            //
            // Add on correction due to kurtosis.
            //
            if (n >= 10)
            {
                w += k * x * (x2 - 3) / 24 + sk * sk * x * (2 * x2 - 5) / -36;
            }

            w = m + sigma * w;
            if (w < DoubleLimits.MinNormalValue)
            {
                return(DoubleLimits.MinNormalValue);
            }
            return(w);
        }
Пример #3
0
        static double InversePoissonCornishFisher(double lambda, double p, double q)
        {
            // mean:
            double m = lambda;
            // standard deviation:
            double sigma = Math.Sqrt(lambda);
            // skewness
            double sk = 1 / sigma;
            // kurtosis:
            // double k = 1/lambda;
            // Get the inverse of a std normal distribution:
            double x = Math2.ErfcInv(p > q ? 2 * q : 2 * p) * Constants.Sqrt2;

            // Set the sign:
            if (p < 0.5)
            {
                x = -x;
            }
            double x2 = x * x;
            // w is correction term due to skewness
            // double w = x + sk * (x2 - 1) / 6;

            double w = x + (x2 - 1) / (6 * sigma);

            //if(lambda >= 10)
            //   w += k * x * (x2 - 3) / 24 + sk * sk * x * (2 * x2 - 5) / -36;

            if (lambda >= 10)
            {
                w += x / 72 * (1 - x2) / lambda;
            }

            w = m + sigma * w;

            return(w);
        }