box muller在c ++中0到1之间的随机数

时间:2017-12-03 03:36:43

标签: c++

我目前正在尝试创建一个高斯随机数生成器,它将生成0到1之间的值。我一直在尝试使用下面的函数,平均值为0,标准差为1,但是当我通过这个生成随机数时使用循环函数,最终我的大部分值都是在[0,1]范围之外生成的。我将如何调整我正在做的事情以将这些值带到该范围内?

float Network::box_muller(float m, float s) {                     
float x1, x2, w, y1;
static float y2;
static int use_last = 0;

if (use_last) {
    y1 = y2;
    use_last = 0;
}
else {
    do {
        x1 = 2.0 * ((double)rand() / (RAND_MAX)) - 1.0;
        x2 = 2.0 * ((double)rand() / (RAND_MAX)) - 1.0;
        w = x1 * x1 + x2 * x2;
    } while (w >= 1.0);

    w = sqrt((-2.0 * log(w)) / w);
    y1 = x1 * w;
    y2 = x2 * w;
    use_last = 1;
}

return(m + y1 * s);
}

2 个答案:

答案 0 :(得分:1)

对于生产代码:

如果您可以访问C ++ 11功能,那么您应该使用std::normal_distribution  (http://en.cppreference.com/w/cpp/numeric/random/normal_distribution)或其变体之一,而不是自己实现功能。这应该给你一个健壮的(不使用rand()),线程安全(你的不是),经过良好测试的实现。

出于学习目的

Wikipedia在C ++中有一个这种算法的示例实现。具体来说,我可以看到您的代码存在两个问题。

  1. 您未正确处理w==0的情况。即log(0)并且除以零是未定义的。

  2. y1y2的更新功能不正确。正确的算法(伪代码):y1 = sqrt(-2 * log(u1)) * cos(2*PI*u2)y2 = sqrt(-2 * log(u1)) * sin(2*PI*u2),其中u1必须在范围(0,1)内,而u2不受约束。

  3. 还有一个小的句法点。您的use_last变量应该是bool,而不是C ++中的int

答案 1 :(得分:0)

你的代码几乎没问题(差不多,因为有时会因为除零而崩溃)。

如果您需要限制在某个范围内的随机数,您可能不希望使用高斯分布。高斯值是无限的。概率在平均值附近迅速下降,但它从未达到确切的零。例如,值超出[m-3 * s的概率; m + 3 * s]间隔仅为0.27%,但不是0.