当随机数生成器被播种后,rand() 是否确实产生了一个随机值?

Does rand() indeed produce a random value when the random number generator has been seeded?

我知道为了避免重复 rand() 函数的相同输出,伪随机数生成器必须使用 srand 函数作为种子。这意味着,如果我尝试说 srand(1)rand() 的输出将是一个值,如果我尝试 srand(2),输出将包含另一个值。但是当我像 srand(1) 一样再次尝试第一个参数时,该值将与第一个输出中的值相同。这个问题让我认为所有随机值都可以某种方式预测。同一个种子是否有可能有不同的输出(比如我明天尝试同一个种子)?还是随机值确实可以预测?

这是 C 标准的语言:

7.22.2 Pseudo-random sequence generation functions

7.22.2.1 The rand function

Synopsis

 #include <stdlib.h>
 int rand(void);

The rand function computes a sequence of pseudo-random integers in the range 0 to RAND_MAX The rand function is not required to avoid data races with other calls to pseudo-random sequence generation functions. The implementation shall behave as if no library function calls the rand function.

Returns

The rand function returns a pseudo-random integer.

Environmental limits

The value of the RAND_MAX macro shall be at least 32767.

7.22.2.2 The srand function

Synopsis

#include <stdlib.h>
void srand(unsigned int seed);

The srand function uses the argument as a seed for a new sequence of pseudo-random numbers to be returned by subsequent calls to rand. If srand is then called with the same seed value, the sequence of pseudo-random numbers shall be repeated. If rand is called before any calls to srand have been made, the same sequence shall be generated as when srand is first called with a seed value of 1.

The srand function is not required to avoid data races with other calls to pseudo-random sequence generation functions. The implementation shall behave as if no library function calls the srand function.

Returns

The srand function returns no value.

换句话说,rand() return 是 0RAND_MAX 之间的 pseudo-random 整数序列。该序列不是随机的,对于传递给 srand() 的每个值都是可预测的,包括从未调用 srand() 的情况。

为了尝试为程序的连续运行获得不同的序列,可以使用快速变化的值调用 srand(),例如 clock() 的 return 值。请注意,调用 srand(time(NULL)) 将在同一秒内为程序的多次运行生成相同的序列。

根据伪随机生成器的传统定义,如果您知道生成器的种子是什么,那么输出值的序列是完全确定的,而不是随机的。这意味着,如果您知道随机生成器的种子,那么您就可以预测该生成器从那时起将产生的每一个输出。 (一个好的随机数生成器是一个看到生成器输出序列不会让你轻易 reverse-engineer 随机种子是什么或预测其他值的随机数生成器。)

我似乎记得前阵子读到过,前阵子,一些流行的扑克网站在选择随机种子方面做得不好。有些人发现你可以输入你看到的牌的图案,然后系统可以 reverse-engineer 随机种子,让你预测所有未来的牌。哎呀。如今,我们拥有基于加密例程的加密安全伪随机生成器,至少就公开文献中已知的内容而言,即使生成器输出的随机位为千兆字节,也无法预测。

如果您确实需要获得一些真正不可预测的东西 - 也就是说,您想要获得一堆真正随机的位 - 您需要使用伪随机数生成器以外的东西。大多数操作系统都有一些机制来生成看起来确实随机的值。例如,他们可能会查看不同的电容器在主板上放电需要多长时间,或者考虑来自时钟的计时信息,或者查看用户如何与键盘交互等。这些数据可以输入到称为一个 熵累加器 慢慢地建立越来越多的随机位。如果您需要一个真正随机且无法提前预测的值,您可以检查您的特定 OS 以了解用于从熵累加器获取数据的机制。 (例如,您可以在 UNIX-style 台机器上读取 /dev/random。)

通常,从熵累加器中提取数据需要时间,因为计算机必须等待足够长的时间才能让足够多的不同来源混合在一起,从而返回 high-quality 随机数据。因此,一种常见的策略是使用熵累加器获得 high-quality 随机种子,然后通过将其用作强伪随机生成器的种子来“拉伸”随机性。