rand() 没有给我一个随机数(即使使用了 srand())

rand() not giving me a random number (even when srand() is used)

好吧,我开始发疯了。我想做的只是在 0 到 410 之间随机选择一个数字,并根据 this page, my code should do that. And since I want a random number and not a pseudo-random number, I'm using srand() as well, in a way that e.g. this 线程告诉我要做的。但这不起作用。我得到的只是一个数字,该数字取决于自上次执行死刑以来的时间。如果我例如尽可能快地再次执行它,该数字通常比上一个数字高 6 个数字,如果我等待更长的时间,它会更高,等等。当它达到 410 时,它会回到 0 并重新开始。我错过了什么?

编辑:哦,如果我删除 srand(time(NULL)); 行,我每次 运行 程序时都会得到相同的数字 (41)。那甚至不是伪随机的,那只是一个静态数字。只是从 the article I linked to above 复制第一行代码仍然给我 41 号。我是 sequel 到 "The Number 23" 中的明星,还是我错过了什么?

int main(void) {

    srand(time(NULL));
    int number = rand() % 410;

    std::cout << number << std::endl;

    system("pause");

}

尝试将 time(NULL) 中的 NULL 更改为 time(0)(这将为您提供当前系统时间)。如果它不起作用,您可以尝试通过执行 time(0)*1000.

将 time(0) 转换为 ms

来自手册:

time() returns the time as the number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).

这意味着如果您在同一秒两次启动您的程序,您将使用相同的值初始化 srand 并将获得相同的 PRNG 状态。

如果您通过调用 srand 删除初始化,您将始终从 rand 获得完全相同的数字序列。

恐怕你不能在那里得到真正的随机数。内置函数旨在提供伪随机数。此外使用 srand 和 rand,因为第一个使用与第二个相同的方法。如果你想烹饪真正的随机数,你必须找到正确的熵源,例如使用大气噪声,如 www.random.org 的方法。

这里的问题在于随机算法使用的种子:如果它是机器提供的数字,它不可能是不可预测的。一个正常的解决方案是使用外部硬件。

这就是使用已弃用的随机数生成的结果。

rand 产生一个固定的数字序列(这本身就很好),而且做得非常非常糟糕。

您通过 srand 告诉 rand 在序列中的何处开始。由于您的 "starting point"(称为 seed btw)取决于自 1.1.1970 0:00:00 UTC 以来的秒数,因此您的输出显然与时间有关。

做您想做的事情的正确方法是使用 C++11 <random> 库。在您的具体示例中,这看起来有点像这样:

std::mt19937 rng (std::random_device{}());
std::uniform_int_distribution<> dist (0, 409);

auto random_number = dist(rng);

有关 rand 的缺点和 <random> 的优点的更多信息,请查看 this

作为最后的评论,像我上面那样播种 std::mt19937 并不是最理想的,因为 MT 的状态 space 比您从一次调用 [=] 中得到的 32 位大得多18=]。这对于玩具程序和您的标准学校作业来说不是问题,但供参考:Here 是我对 MT 的整个状态进行播种的看法 space,以及答案中的一些有用建议。

不幸的是,您无法从没有特定硬件的计算机上获得真实随机数(这通常太慢而不实用)。

因此您需要凑合使用伪生成器。但是你需要小心使用它们。

函数 rand 被设计为 return 0 和 RAND_MAX 之间的数字,从广义上讲,它满足均匀分布的统计特性。充其量您可以期望绘制数字的平均值为 0.5 * RAND_MAX,方差为 RAND_MAX * RAND_MAX / 12.

通常 rand 的实现是一个 线性同余生成器 这基本上意味着 returned 数字是前一个数字的函数。这可以产生出人意料的好结果,并允许您使用函数 为生成器播种 srand.

但是重复使用srand破坏了生成器的统计属性,这就是你正在发生的事情:您对 srand 的使用与您的系统时钟时间相关。您观察到的行为完全符合预期。

您应该做的是只调用一次 srand,然后使用 rand 绘制一系列数字。您无法按照设置的方式轻松地做到这一点。但是还有其他选择;你可以切换到一个随机数生成器(比如梅森旋转器),它允许你绘制第(n)项,你可以将 n 的值作为命令行参数传递。

最后一点,我会避免在绘制数字时使用模数。如果您的模数不是 RAND_MAX.

的倍数,这将产生统计偏差