【发布时间】:2010-09-19 17:58:24
【问题描述】:
我想做的是创建一个函数,该函数接受一个参数,该参数是随机生成应该创建的数字的限制。我经历过一些生成器只是一遍又一遍地重复生成的数字。
如何制作一个不连续返回相同数字的生成器。有人可以帮助我实现我的目标吗?
int randomGen(int max)
{
int n;
return n;
}
【问题讨论】:
我想做的是创建一个函数,该函数接受一个参数,该参数是随机生成应该创建的数字的限制。我经历过一些生成器只是一遍又一遍地重复生成的数字。
如何制作一个不连续返回相同数字的生成器。有人可以帮助我实现我的目标吗?
int randomGen(int max)
{
int n;
return n;
}
【问题讨论】:
从rand 获得均匀分布的结果的最简单方法是这样的:
int limited_rand(int limit)
{
int r, d = RAND_MAX / limit;
limit *= d;
do { r = rand(); } while (r >= limit);
return r / d;
}
结果将在0 到limit-1 的范围内,只要值0 到RAND_MAX 与原始rand 函数的概率相等,每个结果的发生概率都相等。
我使用的其他方法,例如模算术或不带循环的除法会引入偏差。通过浮点中间体的方法不能避免这个问题。从rand 获得好的随机浮点数至少同样困难。如果你想要随机浮点数,使用我的整数函数(或它的改进)是一个很好的起点。
编辑:这里解释一下我所说的偏见。假设 RAND_MAX 是 7,limit 是 5。假设(如果这是一个好的 rand 函数)输出 0、1、2、...、7 的可能性相同。取rand()%5 会将 0、1、2、3 和 4 映射到它们自己,但将 5、6 和 7 映射到 0、1 和 2。这意味着值 0、1 和 2 的可能性是其两倍弹出值 3 和 4。如果您尝试重新缩放和划分,则会发生类似的现象,例如使用 rand()*(double)limit/(RAND_MAX+1) 这里,0 和 1 映射到 0,2 和 3 映射到 1,4 映射到 2、5 和6 映射到 3,7 映射到 4。
RAND_MAX 的大小在一定程度上减轻了这些影响,但如果 limit 很大,它们可能会再次出现。顺便说一句,正如其他人所说,对于线性同余 PRNG(rand 的典型实现),低位往往表现得非常糟糕,所以当limit 是 2 的幂时使用模运算可以避免偏差问题我描述了(因为在这种情况下,limit 通常会平分 RAND_MAX+1),但你会遇到一个不同的问题。
【讨论】:
limit > RAND_MAX,这将导致除以 0。(但是,如果您没有真正从您想要的范围内获得统一的随机数,这可能是件好事。 )
rand 的函数来包装rand 并附加这些位,直到您在一个大范围内获得均匀分布已知固定的二次幂范围。
这个怎么样:
int randomGen(int limit)
{
return rand() % limit;
}
/* ... */
int main()
{
srand(time(NULL));
printf("%d", randomGen(2041));
return 0;
}
【讨论】:
limit 是 2 的幂。
rand 有偏见,那么修复它就更难了……你最好自己写。
任何伪随机生成器都会在一段时间内一遍又一遍地重复这些值。 C只有rand(),如果你使用它,你应该用srand()明确地初始化随机种子。但可能你的平台比这更好。
在 POSIX 系统上,您应该在 man drand48 页面下找到一整套函数。他们有一个明确的时期和质量。您可能会在那里找到您需要的东西。
【讨论】:
在不明确了解您平台的随机生成器的情况下,请勿执行rand() % max。简单随机数生成器的低位字节通常根本不是随机的。
改为使用(返回包含 min 和 max non-inclusive 之间的数字):
int randomIntegerInRange(int min, int max)
{
double tmp = (double)rand() / (RAND_MAX - 1.);
return min + (int)floor(tmp * (max - min));
}
更新:上面的解决方案是有偏差的(参见 cmets 的解释),并且可能不会产生统一的结果。我不删除它,因为它是不该做的事的一个非自然示例。请使用本主题其他地方推荐的拒绝方法。
【讨论】:
max-min 没有均匀地进入RAND_MAX+1,一些输出将比其他输出有更多的输入映射到它们。
rand() 值映射到一个输出整数上,并且可能的输出数量不完全除以可能的 rand() 值的数量,那么将映射一些输出值来自比其他人更少的rand() 值。因此,偏见。