C# 随机高斯变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/218060/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 18:35:25  来源:igfitidea点击:

Random Gaussian Variables

c#.netrandomgaussiannormal-distribution

提问by Sebastian Müller

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

.NET 标准库中是否有一个类可以让我创建遵循高斯分布的随机变量?

采纳答案by yoyoyoyosef

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

Jarrett 的使用 Box-Muller 变换的建议适用于快速而肮脏的解决方案。一个简单的实现:

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)

回答by David Arno

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.aspxand http://www.vbforums.com/showthread.php?t=488959for a third party .NET solutions though.

不过,请查看http://www.extremeoptimization.com/Statistics/UsersGuide/ContinuousDistributions/NormalDistribution.aspxhttp://www.vbforums.com/showthread.php?t=488959以获得第三方 .NET 解决方案。

回答by Jason DeFontes

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

Math.NET Iridium还声称实现了“非均匀随机生成器(正常、泊松、二项式等)”。

回答by Drew Noakes

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.

我在 Microsoft Connect 上创建了对此类功能的请求。如果这是您正在寻找的东西,请为它投票并提高其知名度。

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

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 documentationand is easily ported to C# or other .NET languages.

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

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

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

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

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



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

同时,这里有一个包装器,Random它提供了 Box Muller polar 方法的有效实现:

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

回答by Aaron Stainback

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

你可以试试 Infer.NET。不过,它还没有获得商业许可。这里有链接

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.

它是我的 Microsoft 研究开发的 .NET 概率框架。他们有用于 Bernoulli、Beta、Gamma、Gaussian、Poisson 分布的 .NET 类型,可能还有一些我遗漏了。

It may accomplish what you want. Thanks.

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

回答by Gordon Slysz

Math.NETprovides this functionality. Here's how:

Math.NET提供了此功能。就是这样:

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

您可以在此处找到文档:http: //numerics.mathdotnet.com/api/MathNet.Numerics.Distributions/Normal.htm

回答by Superbest

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

对于 .NET Gaussian 生成,这个问题似乎已经移到了 Google 之上,所以我想我会发布一个答案。

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

为 .NET Random 类制作了一些扩展方法,包括 Box-Muller 变换的实现。由于它们是扩展,只要包含项目(或者您引用编译后的 DLL),您仍然可以执行

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

在此处输入图片说明

回答by Hameer Abbasi

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 almosttwice as fast. It isn't thread-safe, though.

我想扩展@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();
    }
}

回答by Daniel Howard

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.

这是我的简单 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;
   }
} 

回答by Neil

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:

扩展 Drew Noakes 的答案,如果您需要比 Box-Muller 更好的性能(大约快 50-75%),Colin Green 在 C# 中分享了 Ziggurat 算法的实现,您可以在此处找到:

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

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.

Ziggurat 使用查找表来处理离​​曲线足够远的值,它会很快接受或拒绝这些值。大约 2.5% 的时间,它必须做进一步的计算来确定数字位于曲线的哪一侧。