/// <summary> /// Computes the inverse of the cumulative distribution function (InvCDF) for the distribution /// at the given probability. This is also known as the quantile or percent point function. /// </summary> /// <param name="p">The location at which to compute the inverse cumulative density.</param> /// <param name="location">The location (μ) of the distribution.</param> /// <param name="scale">The scale (σ) of the distribution. Range: σ > 0.</param> /// <param name="freedom">The degrees of freedom (ν) for the distribution. Range: ν > 0.</param> /// <returns>the inverse cumulative density at <paramref name="p"/>.</returns> /// <seealso cref="InverseCumulativeDistribution"/> /// <remarks>WARNING: currently not an explicit implementation, hence slow and unreliable.</remarks> public static double InvCDF(double location, double scale, double freedom, double p) { if (scale <= 0.0 || freedom <= 0.0) { throw new ArgumentException(Resources.InvalidDistributionParameters); } // TODO JVG we can probably do a better job for Cauchy special case if (double.IsPositiveInfinity(freedom)) { return(Normal.InvCDF(location, scale, p)); } if (p == 0.5d) { return(location); } // TODO PERF: We must implement this explicitly instead of solving for CDF^-1 return(Brent.FindRoot(x => { var k = (x - location) / scale; var h = freedom / (freedom + (k * k)); var ib = 0.5 * SpecialFunctions.BetaRegularized(freedom / 2.0, 0.5, h); return x <= location ? ib - p : 1.0 - ib - p; }, -800, 800, accuracy: 1e-12)); }