diff --git a/src/Numerics/Distributions/LogNormal.cs b/src/Numerics/Distributions/LogNormal.cs
index a827ecbd..4dd69055 100644
--- a/src/Numerics/Distributions/LogNormal.cs
+++ b/src/Numerics/Distributions/LogNormal.cs
@@ -259,6 +259,7 @@ namespace MathNet.Numerics.Distributions
///
/// The location at which to compute the density.
/// the density at .
+ ///
public double Density(double x)
{
if (x < 0.0)
@@ -275,6 +276,7 @@ namespace MathNet.Numerics.Distributions
///
/// The location at which to compute the log density.
/// the log density at .
+ ///
public double DensityLn(double x)
{
if (x < 0.0)
@@ -291,11 +293,24 @@ namespace MathNet.Numerics.Distributions
///
/// The location at which to compute the cumulative distribution function.
/// the cumulative distribution at location .
+ ///
public double CumulativeDistribution(double x)
{
- return x < 0.0
- ? 0.0
- : 0.5*(1.0 + SpecialFunctions.Erf((Math.Log(x) - _mu)/(_sigma*Constants.Sqrt2)));
+ return x < 0.0 ? 0.0
+ : 0.5*SpecialFunctions.Erfc((_mu - Math.Log(x))/(_sigma*Constants.Sqrt2));
+ }
+
+ ///
+ /// Computes the inverse of the cumulative distribution function (InvCDF) for the distribution
+ /// at the given probability. This is also known as the 'quantile function'.
+ ///
+ /// The location at which to compute the inverse cumulative density.
+ /// the inverse cumulative density at .
+ ///
+ public double InverseCumulativeDistribution(double p)
+ {
+ return p <= 0.0 ? 0.0 : p >= 1.0 ? double.PositiveInfinity
+ : Math.Exp(_mu - _sigma*Constants.Sqrt2*SpecialFunctions.ErfcInv(2.0*p));
}
///
@@ -323,9 +338,10 @@ namespace MathNet.Numerics.Distributions
/// The log-scale (μ) of the distribution.
/// The shape (σ) of the distribution. Range: σ ≥ 0.
/// the density at .
+ ///
public static double PDF(double mu, double sigma, double x)
{
- if (sigma < 0.0) throw new ArgumentOutOfRangeException(Resources.InvalidDistributionParameters);
+ if (sigma < 0.0) throw new ArgumentOutOfRangeException("sigma", Resources.InvalidDistributionParameters);
if (x < 0.0)
{
@@ -343,9 +359,10 @@ namespace MathNet.Numerics.Distributions
/// The log-scale (μ) of the distribution.
/// The shape (σ) of the distribution. Range: σ ≥ 0.
/// the log density at .
+ ///
public static double PDFLn(double mu, double sigma, double x)
{
- if (sigma < 0.0) throw new ArgumentOutOfRangeException(Resources.InvalidDistributionParameters);
+ if (sigma < 0.0) throw new ArgumentOutOfRangeException("sigma", Resources.InvalidDistributionParameters);
if (x < 0.0)
{
@@ -363,15 +380,32 @@ namespace MathNet.Numerics.Distributions
/// The log-scale (μ) of the distribution.
/// The shape (σ) of the distribution. Range: σ ≥ 0.
/// the cumulative distribution at location .
+ ///
public static double CDF(double mu, double sigma, double x)
{
- if (sigma < 0.0) throw new ArgumentOutOfRangeException(Resources.InvalidDistributionParameters);
+ if (sigma < 0.0) throw new ArgumentOutOfRangeException("sigma", Resources.InvalidDistributionParameters);
- return x < 0.0
- ? 0.0
+ return x < 0.0 ? 0.0
: 0.5*(1.0 + SpecialFunctions.Erf((Math.Log(x) - mu)/(sigma*Constants.Sqrt2)));
}
+ ///
+ /// Computes the inverse of the cumulative distribution function (InvCDF) for the distribution
+ /// at the given probability. This is also known as the 'quantile function'.
+ ///
+ /// The location at which to compute the inverse cumulative density.
+ /// The log-scale (μ) of the distribution.
+ /// The shape (σ) of the distribution. Range: σ ≥ 0.
+ /// the inverse cumulative density at .
+ ///
+ public static double InvCDF(double mu, double sigma, double p)
+ {
+ if (sigma < 0.0) throw new ArgumentOutOfRangeException("sigma", Resources.InvalidDistributionParameters);
+
+ return p <= 0.0 ? 0.0 : p >= 1.0 ? double.PositiveInfinity
+ : Math.Exp(mu - sigma*Constants.Sqrt2*SpecialFunctions.ErfcInv(2.0*p));
+ }
+
///
/// Generates a sample from the log-normal distribution using the Box-Muller algorithm.
///
diff --git a/src/Numerics/Distributions/Normal.cs b/src/Numerics/Distributions/Normal.cs
index 737098b4..f7248882 100644
--- a/src/Numerics/Distributions/Normal.cs
+++ b/src/Numerics/Distributions/Normal.cs
@@ -279,6 +279,7 @@ namespace MathNet.Numerics.Distributions
///
/// The location at which to compute the density.
/// the density at .
+ ///
public double Density(double x)
{
var d = (x - _mean)/_stdDev;
@@ -290,6 +291,7 @@ namespace MathNet.Numerics.Distributions
///
/// The location at which to compute the log density.
/// the log density at .
+ ///
public double DensityLn(double x)
{
var d = (x - _mean)/_stdDev;
@@ -301,17 +303,19 @@ namespace MathNet.Numerics.Distributions
///
/// The location at which to compute the cumulative distribution function.
/// the cumulative distribution at location .
+ ///
public double CumulativeDistribution(double x)
{
- return 0.5*(1.0 + SpecialFunctions.Erf((x - _mean)/(_stdDev*Constants.Sqrt2)));
+ return 0.5*SpecialFunctions.Erfc((_mean - x)/(_stdDev*Constants.Sqrt2));
}
///
/// Computes the inverse of the cumulative distribution function (InvCDF) for the distribution
- /// at the given probability.
+ /// at the given probability. This is also known as the 'quantile function'.
///
/// The location at which to compute the inverse cumulative density.
/// the inverse cumulative density at .
+ ///
public double InverseCumulativeDistribution(double p)
{
return _mean - (_stdDev*Constants.Sqrt2*SpecialFunctions.ErfcInv(2.0*p));
@@ -368,6 +372,7 @@ namespace MathNet.Numerics.Distributions
/// The standard deviation (σ) of the normal distribution. Range: σ ≥ 0.
/// The location at which to compute the density.
/// the density at .
+ ///
public static double PDF(double mean, double stddev, double x)
{
if (stddev < 0.0) throw new ArgumentOutOfRangeException("stddev", Resources.InvalidDistributionParameters);
@@ -383,6 +388,7 @@ namespace MathNet.Numerics.Distributions
/// The standard deviation (σ) of the normal distribution. Range: σ ≥ 0.
/// The location at which to compute the density.
/// the log density at .
+ ///
public static double PDFLn(double mean, double stddev, double x)
{
if (stddev < 0.0) throw new ArgumentOutOfRangeException("stddev", Resources.InvalidDistributionParameters);
@@ -398,6 +404,7 @@ namespace MathNet.Numerics.Distributions
/// The mean (μ) of the normal distribution.
/// The standard deviation (σ) of the normal distribution. Range: σ ≥ 0.
/// the cumulative distribution at location .
+ ///
public static double CDF(double mean, double stddev, double x)
{
if (stddev < 0.0) throw new ArgumentOutOfRangeException("stddev", Resources.InvalidDistributionParameters);
@@ -407,12 +414,13 @@ namespace MathNet.Numerics.Distributions
///
/// Computes the inverse of the cumulative distribution function (InvCDF) for the distribution
- /// at the given probability.
+ /// at the given probability. This is also known as the 'quantile function'.
///
/// The location at which to compute the inverse cumulative density.
/// The mean (μ) of the normal distribution.
/// The standard deviation (σ) of the normal distribution. Range: σ ≥ 0.
/// the inverse cumulative density at .
+ ///
public static double InvCDF(double mean, double stddev, double p)
{
if (stddev < 0.0) throw new ArgumentOutOfRangeException("stddev", Resources.InvalidDistributionParameters);
diff --git a/src/UnitTests/DistributionTests/Continuous/LogNormalTests.cs b/src/UnitTests/DistributionTests/Continuous/LogNormalTests.cs
index 84167ef5..eee3f768 100644
--- a/src/UnitTests/DistributionTests/Continuous/LogNormalTests.cs
+++ b/src/UnitTests/DistributionTests/Continuous/LogNormalTests.cs
@@ -523,6 +523,40 @@ namespace MathNet.Numerics.UnitTests.DistributionTests.Continuous
AssertHelpers.AlmostEqual(f, LogNormal.CDF(mu, sigma, x), 8);
}
+ ///
+ /// Validate inverse cumulative distribution.
+ ///
+ /// Mu parameter.
+ /// Sigma value.
+ /// Input X value.
+ /// Expected value.
+ [TestCase(-0.100000, 0.100000, 0.500000, 0.0000000015011556178148777579869633555518882664666520593658)]
+ [TestCase(-0.100000, 0.100000, 0.800000, 0.10908001076375810900224507908874442583171381706127)]
+ [TestCase(-0.100000, 1.500000, 0.100000, 0.070999149762464508991968731574953594549291668468349)]
+ [TestCase(-0.100000, 1.500000, 0.500000, 0.34626224992888089297789445771047690175505847991946)]
+ [TestCase(-0.100000, 1.500000, 0.800000, 0.46728530589487698517090261668589508746353129242404)]
+ [TestCase(-0.100000, 2.500000, 0.100000, 0.18914969879695093477606645992572208111152994999076)]
+ [TestCase(-0.100000, 2.500000, 0.500000, 0.40622798321378106125020505907901206714868922279347)]
+ [TestCase(-0.100000, 2.500000, 0.800000, 0.48035707589956665425068652807400957345208517749893)]
+ [TestCase(1.500000, 1.500000, 0.100000, 0.005621455876973168709588070988239748831823850202953)]
+ [TestCase(1.500000, 1.500000, 0.500000, 0.07185716187918271235246980951571040808235628115265)]
+ [TestCase(1.500000, 1.500000, 0.800000, 0.12532699044614938400496547188720940854423187977236)]
+ [TestCase(1.500000, 2.500000, 0.100000, 0.064125647996943514411570834861724406903677144126117)]
+ [TestCase(1.500000, 2.500000, 0.500000, 0.19017302281590810871719754032332631806011441356498)]
+ [TestCase(1.500000, 2.500000, 0.800000, 0.24533064397555500690927047163085419096928289095201)]
+ [TestCase(2.500000, 1.500000, 0.100000, 0.00068304052220788502001572635016579586444611070077399)]
+ [TestCase(2.500000, 1.500000, 0.500000, 0.016636862816580533038130583128179878924863968664206)]
+ [TestCase(2.500000, 1.500000, 0.800000, 0.034729001282904174941366974418836262996834852343018)]
+ [TestCase(2.500000, 2.500000, 0.100000, 0.027363708266690978870139978537188410215717307180775)]
+ [TestCase(2.500000, 2.500000, 0.500000, 0.10075543423327634536450625420610429181921642201567)]
+ [TestCase(2.500000, 2.500000, 0.800000, 0.13802019192453118732001307556787218421918336849121)]
+ public void ValidateInverseCumulativeDistribution(double mu, double sigma, double x, double f)
+ {
+ var n = new LogNormal(mu, sigma);
+ AssertHelpers.AlmostEqual(x, n.InverseCumulativeDistribution(f), 8);
+ AssertHelpers.AlmostEqual(x, LogNormal.InvCDF(mu, sigma, f), 8);
+ }
+
///
/// Can estimate distribution parameters.
///