C# 正态分布随机数

24
我希望创建一个函数,接受参数 Double meanDouble deviation,并返回符合正态分布的随机数。
例如:如果我传入均值为5.00,标准差为2.00,则68%的时间内我会得到3.00和7.00之间的数字。
我的统计知识有限... 有没有人有想法可以帮助我?我将使用C# 2.0实现,但请自由发挥使用其他编程语言,只要数学函数是标准的即可。
我认为这个链接可能是我需要的东西。你能帮我将其转换为代码吗?
非常感谢您的帮助。

感谢所有参与回复的人。你们指导了我正确的方向。我没有意识到这是一项如此复杂的任务。我本来很确定有人会在短时间内就能提供四行代码。 - J.Hendrix
https://dev59.com/VnVC5IYBdhLWcg3wqzLV - yoyoyoyosef
使用MedallionRandom包,您可以通过mean + (random.NextGaussian() * deviation)实现此目的。 - ChaseMedallion
9个回答

21

请参考这篇CodeProject文章:简单随机数生成。该代码非常简短,可以生成来自均匀、正态和指数分布的样本。


+1 我认为这可能正是我正在寻找的!谢谢。 - J.Hendrix
谢谢,这非常完美。不太长,而且正好做我想要的事情。 - J.Hendrix
简单易用,功能非常棒。干得好! - hagensoft

12

您可能对Math.NET感兴趣,特别是数值计算包。

注意:数值计算包针对的是.NET 3.5版本。如果您的目标版本较早,则可能需要使用Iridium包...


现在看一下http://www.mathdotnet.com/doc/IridiumFeatures.ashx上的功能...不太确定我想要哪个函数。也许是连续概率分布之一?今晚我可能只能下载源代码并仔细研究了。 - J.Hendrix
1
您想使用MathNet.Numerics.Distributions,并执行类似以下的操作,从均值为5.0和标准差为0.68的正态分布中抽取: var mu = 5.00; var sigma = 0.68; var normal = new NormalDistribution(mu, sigma); var draw = normal.NextDouble(); - Mathias

8

这里有一段返回两个值(rand1和rand2)的C代码,因为该算法可以高效地实现此功能。它是Box-Muller变换的极坐标形式。

void RandVal (double mean1, double sigma1, double *rand1, double mean2, double sigma2, double *rand2)
{
double u1, u2, v1, v2, s, z1, z2;

do {
    u1 = Random (0., 1.);  // a uniform random number from 0 to 1
    u2 = Random (0., 1.);
    v1 = 2.*u1 - 1.;
    v2 = 2.*u2 - 1.;
    s = v1*v1 + v2*v2;
} while (s > 1. || s==0.); 

z1 = sqrt (-2.*log(s)/s)*v1;
z2 = sqrt (-2.*log(s)/s)*v2;
*rand1 = (z1*sigma1 + mean1);
*rand2 = (z2*sigma2 + mean2);
return;

}


1
如果您将变量命名为“u”、“v”等,那么命名为“mean”和“sigma”等名称会更有帮助。 - devlord
4
变量u、v、z和s用于与Box-Muller变换中惯用的数学符号保持一致。 - Ian W
4
作为一名导师,我可以证实,如果惯用的数学符号本身被更加描述性地标注,那对大多数人来说会很有帮助。 - Alex Jansen

5

这看起来很有前途。谢谢。 - J.Hendrix

2

抱歉,我没有代码可以提供给你,但我可以指向维基百科上的一些算法。你选择的算法取决于你需要多么精确以及需要多快。


+1 这看起来也不错。我如何创建“两个独立的随机数U和V,均匀分布在(0,1)之间”?抱歉...我告诉过你我的统计知识很薄弱。 - J.Hendrix
在C#中,您可以使用“Random”类(http://msdn.microsoft.com/en-us/library/system.random.aspx)。具体来说,方法NextDouble返回0到1范围内均匀分布的数字。均匀分布意味着您有同等机会获得范围内的任何数字,没有偏向任何特定数字的倾向。 - Martin Sherburn

1

MathNet

来自第二个最佳答案

    public static double GenerateRandomVariant(double mean,double deviation,System.Random rand=null, int factor=1)
    {

        rand = rand ?? new Random();
        double randNormal=(MathNet.Numerics.Distributions.Normal.Sample(rand, mean , deviation));
        return factor * randNormal;

    }

Box-Mueller变换

从顶部答案通过链接获得(速度快两倍?)

由u/yoyoyoyosef提供 随机高斯变量

    public static double GenerateRandomVariant(double mean, double deviation, System.Random rand=null, int factor = 1)
    {
        rand = rand ?? new Random();
        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 +  deviation * randStdNormal); //random normal(mean,stdDev^2)
        return randNormal * factor;
    }

1

对于参考此问题的人,一个简单的解决方案可能是:

Random rand = new Random();
double normRand  = alglib.invnormaldistribution(rand.NextDouble())

根据需要按照 mu 和 sigma 进行缩放。
Alglib 库可在 www.alglib.net 上获取。


0

我知道这篇文章有点老了,但我想分享一个我昨天创建的小项目。 我认为更简单的方法是使用C++ 11并在Managed C++中创建一个.dll文件。 这里有一个链接到源代码和一个已经编译好的dll的zip文件。

以下是我编写的代码:

// NormalDistributionRandom.h
#include <random>

#pragma once

using namespace System;

namespace NormalDistribution 
{

    class _NormalDistributionRandom
    {
        std::default_random_engine engine;
        std::normal_distribution<double> distribution;

    public:
        _NormalDistributionRandom(double mean, double deviation) : distribution(mean, deviation)
        {
        }

        double Next()
        {
            return distribution(engine);
        }
    };

    public ref class NormalDistributionRandom
    {
    private:

        void* Distribution;

    public:

        NormalDistributionRandom( double mean, double deviation)
        {
            Distribution = new _NormalDistributionRandom(mean, deviation);
        }

        double Next()
        {
            return ((_NormalDistributionRandom*)Distribution)->Next();
        }
        ~NormalDistributionRandom()
        {
            this->!NormalDistributionRandom();
        }
    protected:
        !NormalDistributionRandom()
        {
            if (Distribution != nullptr)
            {
                delete (_NormalDistributionRandom*)Distribution;
                Distribution = nullptr;
            }
        }
    };

}

0

MetaNumerics库,也是.NET的,可以快速计算正态分布(以及统计学中的几乎任何其他内容)。请查看功能页面以获取更多详细信息。Codeplex页面在此处:http://metanumerics.codeplex.com/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接