127

Is there a class in the standard library of .NET that gives me the functionality to create random variables that follow Gaussian distribution?

BartoszKP
  • 32,105
  • 13
  • 92
  • 123
Sebastian Müller
  • 5,071
  • 11
  • 49
  • 79
  • 1
    I would just like to add a mathematical result which isn't immediately useful for Normal distributions (due to complex CDF), but is useful for many other distributions. If you put uniformly distributed random numbers in [0,1] (with `Random.NextDouble()`) into the inverse of the CDF of ANY distribution, you will get random numbers that follow THAT distribution. If your application doesn't need precisely normally distributed variables, then the Logistic Distribution is a very close approximation to normal and has an easily invertible CDF. – Ozzah Nov 22 '12 at 23:53
  • 1
    The [MedallionRandom NuGet package](https://github.com/madelson/MedallionUtilities/tree/master/MedallionRandom) contains an extension method for retrieving normally-distributed values from a `Random` using the Box-Muller transform (mentioned in several answers below). – ChaseMedallion May 07 '16 at 14:35
  • [http://mathworld.wolfram.com/Box-MullerTransformation.html](http://mathworld.wolfram.com/Box-MullerTransformation.html) Using two random variables, you can generate random values along a Gaussian distribution. It's not a difficult task at all. – Jarrett Meyer Oct 20 '08 at 12:11

12 Answers12

189

Jarrett's suggestion of using a Box-Muller transform is good for a quick-and-dirty solution. A simple implementation:

Random rand = new Random(); //reuse this if you are generating many
double u1 = 1.0-rand.NextDouble(); //uniform(0,1] random doubles
double u2 = 1.0-rand.NextDouble();
double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) *
             Math.Sin(2.0 * Math.PI * u2); //random normal(0,1)
double randNormal =
             mean + stdDev * randStdNormal; //random normal(mean,stdDev^2)
yoyoyoyosef
  • 6,390
  • 8
  • 36
  • 39
  • 4
    I tested it and compared to MathNet's Mersenne Twister RNG and NormalDistribution. Your version is more than twice as fast and the end result is basically the same (visual inspection of the "bells"). – Johann Gerell Oct 22 '09 at 15:42
  • 5
    @Johann, if you're looking for pure speed, then the [Zigorat Algorithm](http://en.wikipedia.org/wiki/Ziggurat_algorithm) is generally recognised as the fastest approach. Furthermore the above approach can be made faster by carrying a value from one call to the next. – Drew Noakes Jan 04 '11 at 14:49
  • Hi, what should the `stdDev` variable be set to? I understand that this can be configured to specific requirements, but are there any bounds (i.e. max/min values)? – hofnarwillie Aug 22 '13 at 09:05
  • @hofnarwillie stdDev is the scale parameter of the normal distribution, which can be any positive number. The larger it is, the more disperse the generated numbers will be. For a standard normal distribution use parameters mean=0 and stdDev=1. – yoyoyoyosef Aug 26 '13 at 21:14
  • I think `u1` should be `1 - rand.NextDouble()` to avoid log(0)=Inf. The returned numbers by `NextDouble()` are greater or equal to 0 and less than 1. – MBulli Jan 29 '17 at 10:06
  • Don't you need a Math.Abs() around the parameter to Math.Sqrt()? double randStdNormal = Math.Sqrt(Math.Abs(-2 * Math.Log(u1) * Math.Sin(2 * Math.PI * u2))); – Jack Mar 29 '17 at 03:54
  • 1
    @Jack I don't think so. Only the -2*Math.Log(u1) is inside the sqrt, and the log will always be negative or zero since u1<=1 – yoyoyoyosef Mar 29 '17 at 15:51
  • I used above formula and plot it in Excel. It is not good enough Gaussian distribution if you are doing scientific work like me. Use this instead: https://docs.microsoft.com/en-us/dotnet/api/system.web.ui.datavisualization.charting.statisticformula.inversenormaldistribution?view=netframework-4.7.2 – Wayne Lo Dec 01 '18 at 17:27
  • @hofnarwillie my tests show the practical bounds as [-8.5,8.5], which happens when u1 approaches 0 and u2 is either 0.25 (positive result) or 0.75 (negative result). If I set mean=0, stdDev=1, u1=1.0 - 0.99999999999999987 and u2=0.25 (or 0.75) I get +/-8.490424416849509. If u1 goes any lower I get +/- infinity. – AbePralle Dec 03 '19 at 18:25
  • Why do `u2 = 1.0-rand.NextDouble()` ? I think that's not necessary. Only `u1 = 0` is problematic. `Math.Sin` has no problems with 0. – pepoluan May 15 '21 at 16:24
66

This question appears to have moved on top of Google for .NET Gaussian generation, so I figured I'd post an answer.

I've made some extension methods for the .NET Random class, including an implementation of the Box-Muller transform. Since they're extensions, so long as the project is included (or you reference the compiled DLL), you can still do

var r = new Random();
var x = r.NextGaussian();

Hope nobody minds the shameless plug.

Sample histogram of results (a demo app for drawing this is included):

enter image description here

Superbest
  • 22,124
  • 11
  • 54
  • 129
  • Your extension class has a few things I was looking for! thanks! – Thomas Mar 22 '17 at 19:55
  • 1
    you have a small bug in your NextGaussian method. NextDouble() Returns a random floating-point number that is greater than or equal to 0.0, and less than 1.0. So you should have u1 = 1.0 - NextDouble() .... other log(0) will blow up – Mitch Wheat Jan 11 '18 at 04:30
25

Math.NET provides this functionality. Here's how:

double mean = 100;
double stdDev = 10;

MathNet.Numerics.Distributions.Normal normalDist = new Normal(mean, stdDev);
double randomGaussianValue=   normalDist.Sample();

You can find documentation here: http://numerics.mathdotnet.com/api/MathNet.Numerics.Distributions/Normal.htm

Gordon Slysz
  • 903
  • 11
  • 20
  • Great answer! This function is available on NuGet in the [MathNet.Numerics package](https://www.nuget.org/packages/MathNet.Numerics/). Always great not to have to roll your own. – jpmc26 Apr 13 '18 at 21:12
8

I created a request for such a feature on Microsoft Connect. If this is something you're looking for, please vote for it and increase its visibility.

https://connect.microsoft.com/VisualStudio/feedback/details/634346/guassian-normal-distribution-random-numbers

This feature is included in the Java SDK. Its implementation is available as part of the documentation and is easily ported to C# or other .NET languages.

If you're looking for pure speed, then the Zigorat Algorithm is generally recognised as the fastest approach.

I'm not an expert on this topic though -- I came across the need for this while implementing a particle filter for my RoboCup 3D simulated robotic soccer library and was surprised when this wasn't included in the framework.


In the meanwhile, here's a wrapper for Random that provides an efficient implementation of the Box Muller polar method:

public sealed class GaussianRandom
{
    private bool _hasDeviate;
    private double _storedDeviate;
    private readonly Random _random;

    public GaussianRandom(Random random = null)
    {
        _random = random ?? new Random();
    }

    /// <summary>
    /// Obtains normally (Gaussian) distributed random numbers, using the Box-Muller
    /// transformation.  This transformation takes two uniformly distributed deviates
    /// within the unit circle, and transforms them into two independently
    /// distributed normal deviates.
    /// </summary>
    /// <param name="mu">The mean of the distribution.  Default is zero.</param>
    /// <param name="sigma">The standard deviation of the distribution.  Default is one.</param>
    /// <returns></returns>
    public double NextGaussian(double mu = 0, double sigma = 1)
    {
        if (sigma <= 0)
            throw new ArgumentOutOfRangeException("sigma", "Must be greater than zero.");

        if (_hasDeviate)
        {
            _hasDeviate = false;
            return _storedDeviate*sigma + mu;
        }

        double v1, v2, rSquared;
        do
        {
            // two random values between -1.0 and 1.0
            v1 = 2*_random.NextDouble() - 1;
            v2 = 2*_random.NextDouble() - 1;
            rSquared = v1*v1 + v2*v2;
            // ensure within the unit circle
        } while (rSquared >= 1 || rSquared == 0);

        // calculate polar tranformation for each deviate
        var polar = Math.Sqrt(-2*Math.Log(rSquared)/rSquared);
        // store first deviate
        _storedDeviate = v2*polar;
        _hasDeviate = true;
        // return second deviate
        return v1*polar*sigma + mu;
    }
}
Dänu
  • 5,321
  • 9
  • 38
  • 54
Drew Noakes
  • 266,361
  • 143
  • 616
  • 705
  • I got some -ve values from it though. can someone check what's wrong? – mk7 Mar 30 '16 at 04:45
  • @mk7, a Gaussian probability function centred around zero is just as likely to give negative values as it is to give positive values. – Drew Noakes Mar 30 '16 at 07:14
  • You're right! Since I'd like to get a list of weight in a typical population with gaussian PDF, I'm setting mu to, say, 75 [in kg] and sigma to 10. Do I need to set a new instance of GaussianRandom for generating every random weight ? – mk7 Mar 31 '16 at 16:02
  • You can keep drawing samples from the one instance. – Drew Noakes Mar 31 '16 at 16:17
6

Here is another quick and dirty solution for generating random variables that are normal distributed. It draws some random point (x,y) and checks if this point lies under the curve of your probability density function, otherwise repeat.

Bonus: You can generate random variables for any other distribution (e.g. the exponential distribution or poisson distribution) just by replacing the density function.

    static Random _rand = new Random();

    public static double Draw()
    {
        while (true)
        {
            // Get random values from interval [0,1]
            var x = _rand.NextDouble(); 
            var y = _rand.NextDouble(); 

            // Is the point (x,y) under the curve of the density function?
            if (y < f(x)) 
                return x;
        }
    }

    // Normal (or gauss) distribution function
    public static double f(double x, double μ = 0.5, double σ = 0.5)
    {
        return 1d / Math.Sqrt(2 * σ * σ * Math.PI) * Math.Exp(-((x - μ) * (x - μ)) / (2 * σ * σ));
    }

Important: Select the interval of y and the parameters σ and μ so that the curve of the function is not cutoff at it's maximum/minimum points (e.g. at x=mean). Think of the intervals of x and y as a bounding box, in which the curve must fit in.

Doomjunky
  • 928
  • 13
  • 18
  • 4
    Tangenial, but this is actually the first time I've realized you can use Unicode symbols for variables instead of something dumb like _sigma or _phi... – Slothario Jul 31 '19 at 21:16
  • 1
    @Slothario I thank developers everywhere for using 'something dumb' :| – user2864740 Aug 09 '19 at 19:42
5

Math.NET Iridium also claims to implement "non-uniform random generators (normal, poisson, binomial, ...)".

Christoph Rüegg
  • 4,416
  • 1
  • 18
  • 32
Jason DeFontes
  • 2,205
  • 14
  • 14
4

Expanding off of @Noakes and @Hameer's answers, I have also implemented a 'Gaussian' class, but to simplify memory space, I made it a child of the Random class so that you can also call the basic Next(), NextDouble(), etc from the Gaussian class as well without having to create an additional Random object to handle it. I also eliminated the _available, and _nextgauss global class properties, as I didn't see them as necessary since this class is instance based, it should be thread-safe, if you give each thread its own Gaussian object. I also moved all of the run-time allocated variables out of the function and made them class properties, this will reduce the number of calls to the memory manager since the 4 doubles should theoretically never be de-allocated until the object is destroyed.

public class Gaussian : Random
{

    private double u1;
    private double u2;
    private double temp1;
    private double temp2;

    public Gaussian(int seed):base(seed)
    {
    }

    public Gaussian() : base()
    {
    }

    /// <summary>
    /// Obtains normally (Gaussian) distrubuted random numbers, using the Box-Muller
    /// transformation.  This transformation takes two uniformly distributed deviates
    /// within the unit circle, and transforms them into two independently distributed normal deviates.
    /// </summary>
    /// <param name="mu">The mean of the distribution.  Default is zero</param>
    /// <param name="sigma">The standard deviation of the distribution.  Default is one.</param>
    /// <returns></returns>

    public double RandomGauss(double mu = 0, double sigma = 1)
    {
        if (sigma <= 0)
            throw new ArgumentOutOfRangeException("sigma", "Must be greater than zero.");

        u1 = base.NextDouble();
        u2 = base.NextDouble();
        temp1 = Math.Sqrt(-2 * Math.Log(u1));
        temp2 = 2 * Math.PI * u2;

        return mu + sigma*(temp1 * Math.Cos(temp2));
    }
}
2

I'd like to expand upon @yoyoyoyosef's answer by making it even faster, and writing a wrapper class. The overhead incurred may not mean twice as fast, but I think it should be almost twice as fast. It isn't thread-safe, though.

public class Gaussian
{
     private bool _available;
     private double _nextGauss;
     private Random _rng;

     public Gaussian()
     {
         _rng = new Random();
     }

     public double RandomGauss()
     {
        if (_available)
        {
            _available = false;
            return _nextGauss;
        }

        double u1 = _rng.NextDouble();
        double u2 = _rng.NextDouble();
        double temp1 = Math.Sqrt(-2.0*Math.Log(u1));
        double temp2 = 2.0*Math.PI*u2;

        _nextGauss = temp1 * Math.Sin(temp2);
        _available = true;
        return temp1*Math.Cos(temp2);
     }

    public double RandomGauss(double mu, double sigma)
    {
        return mu + sigma*RandomGauss();
    }

    public double RandomGauss(double sigma)
    {
        return sigma*RandomGauss();
    }
}
Hameer Abbasi
  • 1,137
  • 12
  • 30
2

Expanding on Drew Noakes's answer, if you need better performance than Box-Muller (around 50-75% faster), Colin Green has shared an implementation of the Ziggurat algorithm in C#, which you can find here:

http://heliosphan.org/zigguratalgorithm/zigguratalgorithm.html

Ziggurat uses a lookup table to handle values that fall sufficiently far from the curve, which it will quickly accept or reject. Around 2.5% of the time, it has to do further calculations to determine which side of the curve a number is on.

Neil
  • 6,747
  • 4
  • 40
  • 42
0

This is my simple Box Muller inspired implementation. You can increase the resolution to fit your needs. Although this works great for me, this is a limited range approximation, so keep in mind the tails are closed and finite, but certainly you can expand them as needed.

    //
    // by Dan
    // islandTraderFX
    // copyright 2015
    // Siesta Key, FL
    //    
// 0.0  3231 ********************************
// 0.1  1981 *******************
// 0.2  1411 **************
// 0.3  1048 **********
// 0.4  810 ********
// 0.5  573 *****
// 0.6  464 ****
// 0.7  262 **
// 0.8  161 *
// 0.9  59 
//Total: 10000

double g()
{
   double res = 1000000;
   return random.Next(0, (int)(res * random.NextDouble()) + 1) / res;
}

public static class RandomProvider
{
   public static int seed = Environment.TickCount;

   private static ThreadLocal<Random> randomWrapper = new ThreadLocal<Random>(() =>
       new Random(Interlocked.Increment(ref seed))
   );

   public static Random GetThreadRandom()
   {
       return randomWrapper.Value;
   }
} 
mbrig
  • 806
  • 12
  • 15
  • This is my simple Box Muller inspired implementation. You can increase the resolution to fit your needs. This is very fast, simple, and works for my neural net apps which need an approximate Gaussian type of probability density function to get the job done. Hope it helps someone save time and CPU cycles. Although this works great for me, this is a limited range approximation, so keep in mind the tails are closed and finite, but certainly you can expand them as needed. – Daniel Howard Aug 21 '15 at 04:47
  • 1
    Hey Daniel, I've suggested an edit that incorporates the description from your comment into the answer itself. It also removes the '//' that was commenting out the real code in your answer. You can do the edit yourself if you want / if it gets rejected :) – mbrig Jul 19 '16 at 16:30
0

You could try Infer.NET. It's not commercial licensed yet though. Here is there link

It is a probabilistic framework for .NET developed my Microsoft research. They have .NET types for distributions of Bernoulli, Beta, Gamma, Gaussian, Poisson, and probably some more I left out.

It may accomplish what you want. Thanks.

Aaron Stainback
  • 3,164
  • 1
  • 27
  • 31
-1

I don't think there is. And I really hope there isn't, as the framework is already bloated enough, without such specialised functionality filling it even more.

Take a look at http://www.extremeoptimization.com/Statistics/UsersGuide/ContinuousDistributions/NormalDistribution.aspx and http://www.vbforums.com/showthread.php?t=488959 for a third party .NET solutions though.

David Arno
  • 40,354
  • 15
  • 79
  • 124
  • 7
    Since when is Gaussian distribution 'specialised'? It's far more general than, say, AJAX or DataTables. – TraumaPony Oct 20 '08 at 14:49
  • @TraumaPony: are you seriously trying to suggest more developers use Gaussian distribution than use AJAX on a regular basis? – David Arno Oct 20 '08 at 16:53
  • 3
    Possibly; what I'm saying is that it's far more specialised. It only has one use- web apps. Gaussian distributions have an incredible number of unrelated uses. – TraumaPony Oct 21 '08 at 02:34
  • @DavidArno, are you seriously suggesting less functionality improves a framework. – Jodrell Oct 03 '12 at 08:59
  • @Jodrell. Yes. This seems a no-brainer to me. The best frameworks are small, targeted-functionality frameworks. Kitchen-sink frameworks are a nightmare to learn and use. They best belong in the JEE world. – David Arno Oct 03 '12 at 13:15
  • 1
    @Jodrell, to cite a specific example, I think the decision to make MVC a separate framework, rather than part of the main .NET framework, was a good one. – David Arno Oct 03 '12 at 13:24
  • but they could put it in the math lib as an extension for random :) – WiiMaxx Jul 29 '13 at 14:10