/// <summary> /// Returns the next representable value after x in the direction of y. /// </summary> /// <param name="x">the value to get the next of</param> /// <param name="y">direction</param> /// <returns> /// The next floating point value in the direction of y /// <para>If x == NaN || x == Infinity, returns NaN</para> /// <para>If y == NaN, returns NaN</para> /// <para>If y > x, returns FloatNext(x)</para> /// <para>If y = x, returns x</para> /// <para>If y < x, returns FloatPrior(x)</para> /// </returns> public static double Nextafter(double x, double y) { if ((double.IsNaN(x) || double.IsInfinity(x)) || (double.IsNaN(y))) { Policies.ReportDomainError("Nextafter(x: {0}, y: {1}): Requires finite x, y not NaN", x, y); return(double.NaN); } if (y > x) { return(Math2.FloatNext(x)); } if (y == x) { return(x); } return(Math2.FloatPrior(x)); }
public static double ImpQ(double z, double p, double q) { Debug.Assert(q <= 0.5); if (q == 0) { return(DoubleLimits.MinNormalValue); } #if EXTRA_DEBUG var gs = new Stack <double>(); #endif // Set outside limits // Since Q(a, z) > 1/2 for a >= z+1, so maxA < z+1 double minA = DoubleLimits.MinNormalValue; double maxA = z + 1; if (maxA == z) { maxA = Math2.FloatNext(z); } double step = 0.5; double aGuess = 0; // We can use the relationship between the incomplete // gamma function and the poisson distribution to // calculate an approximate inverse. // Mostly it is pretty accurate, except when a is small or q is tiny. // Case 1: a <= 1 : Inverse Cornish Fisher is unreliable in this area var e = Math.Exp(-z); if (q <= e) { if (q == e) { return(1); } maxA = 1; // If a <= 1, P(a, x) = 1 - Q(a, x) >= (1-e^-x)^a var den = (z > 0.5) ? Math2.Log1p(-Math.Exp(-z)) : Math.Log(-Math2.Expm1(-z)); var limit = Math2.Log1p(-q) / den; if (limit < 1) { minA = Math.Max(minA, limit); } step = (1 - minA) * 0.125; aGuess = minA * (1 + step); if (minA < 0.20) { // Use a first order approximation Q(a, z) at a=0 // Mathematica: Assuming[ a >= 0 && z > 0, FunctionExpand[Normal[Series[GammaRegularized[a, z], {a, 0, 1}]]]] // q = -a * ExpIntegralEi[-z] // The smaller a is the better the guess // as z->0 term2/term1->1/2*Log[z], which is adequate for double precision aGuess = -q / Math2.Expint(-z); if (aGuess <= DoubleLimits.MachineEpsilon) { ExtraDebugLog(z, p, q, aGuess, aGuess, step, minA, maxA, 0, ""); return(aGuess); } step = aGuess * 0.125; } else if (minA >= 0.40) { // Use a first order approximation Q(a, z) at a=1 // Mathematica: Assuming[ a >= 0 && z > 0, FunctionExpand[Normal[Series[GammaRegularized[a, z], {a, 1, 1}]]]] var d = Math.Exp(-z) * (Math.Log(z) + Constants.EulerMascheroni) + Math2.Expint(1, z); aGuess = (q - Math.Exp(-z)) / d + 1; } aGuess = Math.Max(aGuess, minA); aGuess = Math.Min(aGuess, maxA); var r = SolveA(z, p, q, aGuess, step, minA, maxA); ExtraDebugLog(z, p, q, r.Result, aGuess, step, minA, maxA, r.Iterations, ""); return(r.Result); } // Case 2: a > 1 : Inverse Poisson Corning Fisher approximation improves as a->Infinity minA = 1; aGuess = 0.5 + InversePoissonCornishFisher(z, q, p); if (aGuess > 100) { step = 0.01; } else if (aGuess > 10) { step = 0.01; } else { // our poisson approximation is weak. step = 0.05; } #if EXTRA_DEBUG double og = aGuess; #endif aGuess = Math.Max(aGuess, minA); aGuess = Math.Min(aGuess, maxA); #if EXTRA_DEBUG if (og != aGuess) { gs.Push(og); } #endif // For small values of q, our Inverse Poisson Cornish Fisher guess can be way off // Try to come up with a better guess if (q < DoubleLimits.MachineEpsilon) { step *= 10; if (Math.Abs((aGuess - 1) / z) < 1.0 / 8) { #if EXTRA_DEBUG double old = aGuess; #endif (aGuess, _) = RefineQ_SmallA_LargeZ(z, p, q, aGuess); #if EXTRA_DEBUG if (old != aGuess) { gs.Push(old); } #endif } } var rr = SolveA(z, p, q, aGuess, step, minA, maxA); #if EXTRA_DEBUG if (rr.Iterations > 6) { string guesses = (gs.Count == 0) ? string.Empty : ", og: (" + string.Join(", ", gs) + ")"; ExtraDebugLog(z, p, q, rr.Result, aGuess, step, minA, maxA, rr.Iterations, guesses); } #endif return(rr.Result); }