C# 用C语言实现Box-Mueller随机数发生器#

C# 用C语言实现Box-Mueller随机数发生器#,c#,random,non-uniform-distribution,C#,Random,Non Uniform Distribution,因为我以前遇到过这样的随机数生成器,所以我做了一些研究。我只记得“米勒”这个名字,所以我想我在这里找到了它: 我可以在其他语言中找到它的许多实现,但我似乎无法在C#中正确实现它 例如,本页说明代码应如下所示(这不是C#): 我的问题是在以下特定场景中,我的代码不返回0-1范围内的值,我也不理解原始代码是如何返回的 u=0.5,v=0.1 S变为0.5*0.5+0.1*0.1=0.26 fac变为~3.22 因此,返回值为~0.5*3.22或~1.6 这不在0。。1 我做错了什么/不理解

因为我以前遇到过这样的随机数生成器,所以我做了一些研究。我只记得“米勒”这个名字,所以我想我在这里找到了它:

我可以在其他语言中找到它的许多实现,但我似乎无法在C#中正确实现它

例如,本页说明代码应如下所示(这不是C#):

我的问题是在以下特定场景中,我的代码不返回0-1范围内的值,我也不理解原始代码是如何返回的

  • u=0.5,v=0.1
  • S变为
    0.5*0.5+0.1*0.1
    =
    0.26
  • fac变为~
    3.22
  • 因此,返回值为~
    0.5*3.22
    或~
    1.6
这不在
0。。1

我做错了什么/不理解


如果我修改代码,将
fac
u
相乘,而不是与
S
相乘,则得到的值范围为0到1,但分布不正确(似乎最大分布在0.7-0.8之间,然后在两个方向上逐渐变细)。

我认为函数返回极坐标。因此,需要两个值才能得到正确的结果


此外,高斯分布不在
0之间。。1
。结果很容易达到1000,但发生这种情况的概率极低。

我不是数学家或统计学家,但如果我考虑到这一点,我不会期望高斯分布返回精确范围内的数字。根据您的实现,平均值为0,标准偏差为1,因此我希望数值分布在钟形曲线上,中间为0,然后随着数值在两侧偏离0而减小。所以这个序列肯定会覆盖两个+/-数字


既然它是统计的,为什么仅仅因为std.dev是1就很难限制为-1..1呢?从统计上看,两边都有一些间隙,但仍然满足统计要求。

均匀随机变量确实在0..1范围内,但高斯随机变量(这是Box-Muller算法生成的)可以位于实线的任何位置。有关详细信息,请参阅。

您的代码很好。您的错误是认为它应该只返回
[0,1]
中的值。(标准)正态分布是在整条实线上具有非零权重的分布。也就是说,可以使用
[0,1]
之外的值。事实上,
[-1,0]
中的值与
[0,1]
中的值一样可能,而且,
[0,1]
的补码约占正态分布权重的66%。因此,66%的时间我们期望值超出
[0,1]


此外,我认为这不是Box-Mueller变换,而是Marsaglia极坐标法。

这是一种蒙特卡罗方法,因此不能钳制结果,但可以忽略样本

// return random value in the range [0,1].
double gaussian_random()
{
    double sigma = 1.0/8.0; // or whatever works.
    while ( 1 ) {
        double z = gaussian() * sigma + 0.5;
        if (z >= 0.0 && z <= 1.0)
            return z;
    }
}
//返回[0,1]范围内的随机值。
双高斯随机
{
双西格玛=1.0/8.0;//或任何有效的方法。
而(1){
双z=高斯()*西格玛+0.5;

如果(z>=0.0&&z请注意,我已经检查了上述代码的两个示例,通常是C或Java,它们看起来几乎相同。您确定C代码生成的正是您想要的吗?在文献中,他们称之为Box-Muller极坐标形式,请参阅
public static double NextGaussianDouble(this Random r)
{
    double u, v, S;

    do
    {
        u = 2.0 * r.NextDouble() - 1.0;
        v = 2.0 * r.NextDouble() - 1.0;
        S = u * u + v * v;
    }
    while (S >= 1.0);

    double fac = Math.Sqrt(-2.0 * Math.Log(S) / S);
    return u * fac;
}
// return random value in the range [0,1].
double gaussian_random()
{
    double sigma = 1.0/8.0; // or whatever works.
    while ( 1 ) {
        double z = gaussian() * sigma + 0.5;
        if (z >= 0.0 && z <= 1.0)
            return z;
    }
}