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

有帮助吗?

解决方案

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)

其他提示

这个问题似乎已经转移到谷歌的.NET高斯世代,所以我想我会发一个答案。

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

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

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

结果的示例直方图(包括用于绘制它的演示应用程序):

Math.NET 提供此功能。方法如下:

double mean = 100;
double stdDev = 10;

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

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

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

https://connect.microsoft。 COM / VisualStudio的/反馈/信息/ 634346 /高斯正态分布,随机数

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

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

我不是这方面的专家 - 我在实施时遇到了这方面的需求我的 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 Iridium 也声称实施了“非均匀随机生成器”(普通,泊松,二项式) ,...)&quot;。

这是另一个快速而又脏的解决方案,用于生成正态分布的随机变量。它绘制一些随机点(x,y)并检查此点是否位于概率密度函数的曲线下,否则重复。

奖励:您可以为任何其他发行版生成随机变量(例如指数分布或只需更换密度函数,即可泊松分布

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

重要提示:选择 y 的间隔以及参数&#963; &#956; 以便功能曲线在它的最大/最小点处没有截止(例如,在x =平均值时)。将 x y 的区间想象为一个边界框,其中曲线必须适合。

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

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

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

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

扩展了@Noakes和@Hameer的答案,我还实现了一个'Gaussian'类,但是为了简化内存空间,我把它变成了Random类的一个子类,这样你也可以调用基本的Next(),来自Gaussian类的NextDouble()等,无需创建额外的Random对象来处理它。我还删除了_available和_nextgauss全局类属性,因为我没有看到它们是必要的,因为这个类是基于实例的,它应该是线程安全的,如果你给每个线程自己的高斯对象。我还将所有运行时分配的变量移出函数并使它们成为类属性,这将减少对内存管理器的调用次数,因为理论上理论上永远不会取消分配4个双精度,直到对象被销毁。 / p>

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

您可以尝试使用Infer.NET。但它尚未获得商业许可。这里有链接

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

它可以完成你想要的。感谢。

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

我认为没有。我真的希望没有,因为框架已经足够膨胀,没有这样的专业功能,甚至更多。

请参阅 http://www.extremeoptimization.com/Statistics /UsersGuide/ContinuousDistributions/NormalDistribution.aspx http://www.vbforums .com / showthread.php?t = 488959 ,但第三方.NET解决方案。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top