/// <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)); }
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); }
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); }