【发布时间】:2014-12-31 03:17:03
【问题描述】:
我目前正在使用 C 来生成高斯噪声。一步,我需要记录一个均匀分布的数字u1 = (double) rand() / RAND_MAX。因为u1 可能为零,所以做log(u1) 是有风险的。所以,我需要检查一下。我应该使用
do {
u1 = ((double) rand() / RAND_MAX);
} while (u1 == 0.);
或者,我应该使用
do {
u1 = ((double) rand() / RAND_MAX);
} while (u1 < epsilon);
epsilon 是一个小数字吗?如果首选后者,我应该如何选择 epsilon 的值? (在 Fortran 中有TINY,但我不知道用 C 做什么)。
附上完整代码:
#include <stdio.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include <stdlib.h>
double gaussian_noise(double mean, double std)
{
static int have_spare = 0;
static double u1, u2, z1, z2;
if(have_spare)
{
have_spare = 0;
z2 = sqrt(-2. * log(u1)) * sin(2. * M_PI * u2);
return mean + std * z2;
}
have_spare = 1;
do {
u1 = ((double) rand() / RAND_MAX);
} while (u1 == 0.);
u2 = ((double) rand() / RAND_MAX);
z1 = sqrt(-2. * log(u1)) * cos(2. * M_PI * u2);
return mean + std * z1;
}
void main()
{
const double mean = 0., std = 1.;
double noise;
int i;
for(i=0; i<100000; i++)
{
noise = gaussian_noise(mean, std);
printf("%lf\t", noise);
}
}
【问题讨论】:
-
只检查 0 就足够了。最小值 (Double.MIN_VALUE) 的对数产生明确定义的数字。
-
应该按原样工作。 Fortran 中的 Wrt TINY,C 中的头文件
有很多相关的常量,请检查它 -
1.0/RAND_MAX仍然比RAND_MAX == INT_MAX的最小正双精度值大近 600 倍,所以您不必担心 -
您可以使用
(rand() + 1.0) / (RAND_MAX + 1.0)跳过循环。请注意,对于大多数 C 库,rand()是一个 terrible 随机数生成器。如果您将结果用于任何严肃的应用程序,请获得更好的应用程序。
标签: c random gaussian divide-by-zero