随机高斯variables

在.NET的标准库中是否有一个类给我提供了创build遵循高斯分布的随机variables的function?

Jarrett提出的使用Box-Muller变换的build议对于一个快速和肮脏的解决scheme来说是很好的。 一个简单的实现:

 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) 

这个问题似乎已经在Google for .NET高斯一代之上,所以我想我会发表一个答案。

我已经为.NET Random类做了一些扩展方法 ,包括Box-Muller变换的实现。 既然它们是扩展名,只要包含项目(或者引用编译后的DLL),你仍然可以这样做

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

希望没有人介意无耻的插件。

结果的样本直方图(包括一个演示应用程序):

在这里输入图像说明

http://mathworld.wolfram.com/Box-MullerTransformation.html

使用两个随机variables,您可以生成沿高斯分布的随机值。 这根本不是一件困难的事情。

我在Microsoft Connect上创build了这样一个function的请求。 如果这是你正在寻找的东西,请投票支持,并提高其知名度。

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

该function包含在Java SDK中。 它的实现可作为文档的一部分,并且可以轻松移植到C#或其他.NET语言。

如果您正在寻找纯粹的速度,那么Zigoratalgorithm通常被认为是最快的方法。

我不是这个话题的专家 – 我遇到了这个需求,同时为我的RoboCup 3D模拟机器人足球库实现一个粒子滤波器 ,并且当它没有被包含在框架中时,感到很惊讶。


同时,下面是Random的一个包装器,它提供了Box Muller极坐标法的有效实现:

 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; } } 

Math.NET提供了这个function。 就是这样:

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

你可以在这里find文档: http : //numerics.mathdotnet.com/api/MathNet.Numerics.Distributions/Normal.htm

Math.NET铱星也声称实施“非均匀随机生成器(正常,泊松,二项式,…)”。

我想扩大@Yoyoyoyosef的答案,使其更快,并编写一个包装类。 发生的开销可能并不意味着两倍,但我认为应该一倍。 不过,这不是线程安全的。

 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(); } } 

这是我的简单Box Muller启发实施。 您可以增加分辨率以适应您的需求。 虽然这对我来说很好,但这是一个有限范围的近似值,所以记住尾巴是封闭的和有限的,但是当然你可以根据需要扩展它们。

  // // 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; } } 

在Drew Noakes的回答中,如果您需要比Box-Muller更好的性能(大约快50-75%),Colin Green已经在C#中分享了Zigguratalgorithm的实现,您可以在这里find:

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

Ziggurat使用查找表来处理距离曲线足够远的值,它将快速接受或拒绝。 大约2.5%的时间,它必须做进一步的计算,以确定曲线的哪一侧是一个数字。

这是另一个快速而肮脏的解决scheme,用于生成正态分布的随机variables。 它绘制一些随机点(x,y),并检查这个点是否在你的概率密度函数的曲线之下,否则重复。

奖金:您可以通过replace密度函数来为任何其他分布(例如指数分布或泊松分布 )生成随机variables。

  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 * σ * σ)); } 

重要事项:selecty的间隔和参数σμ ,以使函数的曲线在最大/最小点(例如x =平均值)处不被截断。 把xy的区间想象成一个边界框,其中曲线必须适合。

你可以尝试Infer.NET。 虽然没有商业许可。 这里有链接

这是一个.NET的概率框架开发我的微软研究。 他们有分布的伯努利,贝塔,伽玛,高斯,泊松的.NETtypes,可能还有一些我遗漏了。

它可能会完成你想要的。 谢谢。

我不认为有。 我真的希望没有,因为框架已经够臃肿,没有这种专门的function填充它甚至更多。

尽pipe如此, 请参阅http://www.extremeoptimization.com/Statistics/UsersGuide/ContinuousDistributions/NormalDistribution.aspx和http://www.vbforums.com/showthread.php?t=488959了解第三方;.NET解决scheme。