关于RNG,我有三个问题。
首先是哪些数据可用作种子。我一直在利用时间,但必须有其他容易获得的种子。
c++中有哪些容易获得的种子?
如果我根据从 RNG 中出来的下一个值以随机间隔重新播种 RNG,并从问题 1 的答案中随机选择种子,这会创建一个更难预测并因此更随机的伪随机链吗?
最后,在 c++ 中获得一个范围内的随机数的最佳方法是什么?我一直在使用模数运算符,但我想要在范围内均匀分布的东西,而不是像 AI 决策那样偏向高或低。
这取决于你需要什么rand
。对于很多用途,time
是完全足够的。对于其他人来说则更少。我通常会从 Unix 机器上读取四个字节,如果
不可用则/dev/random
恢复。更有效的解决方案是使用更高分辨率的计时器,并在进程或机器 ID 等内容中进行散列。time
/dev/random
除非您使用类似的方法,否则重新播种可能不会改变太多/dev/random
。大多数其他可用值都是可以预测的。
如果RAND_MAX
是范围的倍数,则模可以正常工作。如果不是,唯一的解决方案是丢弃值:你有一个总值
RAND_MAX + 1
,你需要n
. 并且没有可能的映射将所有RAND_MAX + 1
值映射到n
每个 并且具有相同数量的输入n
。通常的解决方案是:
整数限制 = (RAND_MAX + 1) - (RAND_MAX + 1) % n; int 结果 = rand(); 而(结果>=限制) 结果 = 兰德(); 返回结果%n;
(我在这里假设您正在寻找范围内的结果
[0...n)
。这RAND_MAX + 1
不会溢出。)
最后,如果您担心随机值的质量,请注意许多实现rand()
并不是特别好。您可能想要切换到增强随机生成器之一。
你应该看看boost::random
。
记住:
我希望您可以简单地使用boost::mt19937
,但这实际上取决于应用程序。
RNG 的一个容易获得的种子是任何时间函数。种子不需要是随机的,只要每次启动程序都不同,这就足够了。试图使伪随机数“更随机”是一项有点愚蠢的努力。如果需要,那么生成器就不值得了。
此外,除非用真正的随机噪声定期播种,否则无论如何您都不会使输出“更加随机”,如果您定期播种真正的随机噪声,那么只有种子才是真正随机的,其他值仍然是确定性的,并且总共有与此生成器生成的任何其他序列具有相同的统计属性。
如果偏斜分布不可接受,则在非二次幂范围内获取数字的通常实现看起来有点像:
range = high - low;
while((r = rand()) > range) {}
r += low;
模数和乘法/除法具有众所周知的歪斜和溢出问题。
不过,如果是如你所说的人工智能决策,我敢说,如果一个结果的可能性比另一个结果高 1%,我敢说没有人会注意到。因此,简单地使用模可能就足够了,具有确定的时间,而且非常简单。另请注意,您始终可以选择一个适用于模数的范围。
对于大多数应用程序来说,时间已经足够了,如果您需要更好的随机数,那么您应该查看提供此类功能的特定库。
对于范围生成,以下内容不会扭曲结果:
int random = rand() * RANGE / RAND_MAX;