diff --git a/src/Numerics/Distributions/TruncatedNormal.cs b/src/Numerics/Distributions/TruncatedNormal.cs
new file mode 100644
index 00000000..72c8d271
--- /dev/null
+++ b/src/Numerics/Distributions/TruncatedNormal.cs
@@ -0,0 +1,246 @@
+//
+// Math.NET Numerics, part of the Math.NET Project
+// http://numerics.mathdotnet.com
+// http://github.com/mathnet/mathnet-numerics
+// http://mathnetnumerics.codeplex.com
+//
+// Copyright (c) 2009-2013 Math.NET
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using MathNet.Numerics.Properties;
+using MathNet.Numerics.Random;
+
+namespace MathNet.Numerics.Distributions {
+
+ ///
+ /// Truncated Normal Distribution.
+ /// For more details about this distribution, see
+ /// Wikipedia - Truncated normal distribution
+ ///
+ public class TruncatedNormal : IContinuousDistribution {
+
+ System.Random _random;
+
+ readonly double _mean;
+ readonly double _stdDev;
+ readonly double _lowerBound;
+ readonly double _upperBound;
+ readonly Normal _uncorrectedNormal;
+ ///
+ /// The total density of the uncorrected normal distribution which is within the lower and upper bounds.
+ ///
+ readonly double _cumulativeDensityWithinBounds;
+
+ ///
+ /// Initializes a new instance of the TruncatedNormal class with a particular mean, standard deviation, lower bound, and upper bound. The distribution will
+ /// be initialized with the default random number generator. The mean and standard deviation are that of the untruncated
+ /// normal distribution.
+ ///
+ /// The mean (μ) of the untruncated distribution.
+ /// The standard deviation (σ) of the untruncated distribution. Range: σ ≥ 0.
+ /// The inclusive lower bound of the truncated distribution. Default is double.NegativeInfinity.
+ /// The inclusive upper bound of the truncated distribution. Must be larger than .
+ /// Default is double.PositiveInfinity.
+ public TruncatedNormal(double mean, double stddev, double lowerBound = double.NegativeInfinity, double upperBound = double.PositiveInfinity)
+ :this(mean, stddev, SystemRandomSource.Default, lowerBound, upperBound)
+ {
+
+ }
+
+ ///
+ /// Initializes a new instance of the Normal class with a particular mean and standard deviation. The distribution will
+ /// be initialized with the default random number generator.
+ ///
+ /// The mean (μ) of the normal distribution.
+ /// The standard deviation (σ) of the normal distribution. Range: σ ≥ 0.
+ /// The random number generator which is used to draw random samples.
+ public TruncatedNormal(double mean, double stddev, System.Random randomSource, double lowerBound = double.NegativeInfinity, double upperBound = double.PositiveInfinity)
+ {
+ if (!IsValidParameterSet(mean, stddev, lowerBound, upperBound))
+ {
+ throw new ArgumentException(Resources.InvalidDistributionParameters);
+ }
+
+ _random = randomSource ?? SystemRandomSource.Default;
+ _mean = mean;
+ _stdDev = stddev;
+ _lowerBound = lowerBound;
+ _upperBound = upperBound;
+ _uncorrectedNormal = Normal.WithMeanStdDev(_mean, _stdDev);
+ _cumulativeDensityWithinBounds = _uncorrectedNormal.CumulativeDistribution(_upperBound) - _uncorrectedNormal.CumulativeDistribution(_lowerBound);
+ }
+
+ ///
+ /// Tests whether the provided values are valid parameters for this distribution.
+ ///
+ /// The mean (μ) of the normal distribution.
+ /// The standard deviation (σ) of the normal distribution. Range: σ ≥ 0.
+ public static bool IsValidParameterSet(double mean, double stddev, double lowerBound, double upperBound)
+ {
+ bool normalRequirements = Normal.IsValidParameterSet(mean, stddev);
+ bool boundsAreOrdered = lowerBound < upperBound;
+ return normalRequirements && boundsAreOrdered;
+ }
+
+ public override string ToString() {
+ return "TruncatedNormal(μ = " + _mean + ", σ = " + _stdDev +", LowerBound = " + _lowerBound + ", UpperBound = " + _upperBound + ")";
+ }
+
+ ///
+ /// Gets the mode of the normal distribution.
+ ///
+ public double Mode
+ {
+ get
+ {
+ if (_mean < _lowerBound)
+ return _lowerBound;
+ if (_mean > _upperBound)
+ return _upperBound;
+ return _mean;
+ }
+ }
+
+ ///
+ /// Gets the minimum of the truncated normal distribution.
+ ///
+ public double Minimum
+ {
+ get { return _lowerBound; }
+ }
+
+ ///
+ /// Gets the maximum of the truncated normal distribution.
+ ///
+ public double Maximum
+ {
+ get { return _upperBound; }
+ }
+
+ public double Mean
+ {
+ get
+ {
+ var pdfDifference = _uncorrectedNormal.Density(_lowerBound) - _uncorrectedNormal.Density(_upperBound);
+ var diffFromUncorrected = pdfDifference * _stdDev / _cumulativeDensityWithinBounds;
+ return _mean + diffFromUncorrected;
+ }
+ }
+
+ public double Variance {
+ get {
+ throw new NotImplementedException();
+ }
+ }
+
+ public double StdDev {
+ get {
+ throw new NotImplementedException();
+ }
+ }
+
+ public double Entropy {
+ get {
+ throw new NotImplementedException();
+ }
+ }
+
+ public double Skewness {
+ get {
+ throw new NotImplementedException();
+ }
+ }
+
+ public double Median {
+ get {
+ throw new NotImplementedException();
+ }
+ }
+
+ ///
+ /// Gets or sets the random number generator which is used to draw random samples.
+ ///
+ public System.Random RandomSource
+ {
+ get { return _random; }
+ set { _random = value ?? SystemRandomSource.Default; }
+ }
+
+ ///
+ /// Computes the probability density of the distribution (PDF) at x, i.e. ∂P(X ≤ x)/∂x.
+ ///
+ /// The location at which to compute the density.
+ /// the density at .
+ ///
+ public double Density(double x)
+ {
+ if (x < _lowerBound || _upperBound < x)
+ return 0d;
+
+ return _uncorrectedNormal.Density(x) / (_stdDev * _cumulativeDensityWithinBounds);
+ }
+
+ ///
+ /// Computes the log probability density of the distribution (lnPDF) at x, i.e. ln(∂P(X ≤ x)/∂x).
+ ///
+ /// The location at which to compute the log density.
+ /// the log density at .
+ ///
+ public double DensityLn(double x)
+ {
+ return Math.Log(Density(x));
+ }
+
+ public double Sample() {
+ throw new NotImplementedException();
+ }
+
+ public void Samples(double[] values) {
+ throw new NotImplementedException();
+ }
+
+ public IEnumerable Samples() {
+ throw new NotImplementedException();
+ }
+
+ ///
+ /// Computes the cumulative distribution (CDF) of the distribution at x, i.e. P(X ≤ x).
+ ///
+ /// The location at which to compute the cumulative distribution function.
+ /// the cumulative distribution at location .
+ ///
+ public double CumulativeDistribution(double x)
+ {
+ if (x < _lowerBound)
+ return 0d;
+ if (x > _upperBound)
+ return 1d;
+
+ double cumulative = _uncorrectedNormal.CumulativeDistribution(x) - _uncorrectedNormal.CumulativeDistribution(_lowerBound);
+ return cumulative / _cumulativeDensityWithinBounds;
+ }
+ }
+}
diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj
index 9bfd671b..564c25ed 100644
--- a/src/Numerics/Numerics.csproj
+++ b/src/Numerics/Numerics.csproj
@@ -90,6 +90,7 @@
+