我目前正在尝试创建一个高斯随机数生成器,它将生成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);
}
答案 0 :(得分:1)
对于生产代码:
如果您可以访问C ++ 11功能,那么您应该使用std::normal_distribution
(http://en.cppreference.com/w/cpp/numeric/random/normal_distribution)或其变体之一,而不是自己实现功能。这应该给你一个健壮的(不使用rand()
),线程安全(你的不是),经过良好测试的实现。
出于学习目的
Wikipedia在C ++中有一个这种算法的示例实现。具体来说,我可以看到您的代码存在两个问题。
您未正确处理w==0
的情况。即log(0)
并且除以零是未定义的。
y1
和y2
的更新功能不正确。正确的算法(伪代码):y1 = sqrt(-2 * log(u1)) * cos(2*PI*u2)
和y2 = sqrt(-2 * log(u1)) * sin(2*PI*u2)
,其中u1
必须在范围(0,1)内,而u2不受约束。
还有一个小的句法点。您的use_last
变量应该是bool
,而不是C ++中的int
。
答案 1 :(得分:0)
你的代码几乎没问题(差不多,因为有时会因为除零而崩溃)。
如果您需要限制在某个范围内的随机数,您可能不希望使用高斯分布。高斯值是无限的。概率在平均值附近迅速下降,但它从未达到确切的零。例如,值超出[m-3 * s的概率; m + 3 * s]间隔仅为0.27%,但不是0.