【问题标题】:Does C's rand() have to be random?C 的 rand() 必须是随机的吗?
【发布时间】:2017-04-04 06:11:14
【问题描述】:

我试图在 C 中获取有关 rand() 规范和实现的一些信息,但我找不到太多信息。事实上,我找不到任何东西除了:

  • rand() 在函数调用之间不前进
  • 相同的种子总是产生相同的数字
  • 随机数介于 0 和 RAND_MAX 之间

值得注意的是,这些东西都不需要随机性。具体来说,我没有看到任何禁止这种实现的东西:

int randval = 0;

void srand(unsigned int seed) {
    randval = seed;
    return;
}

int rand() {
    return randval++;
}

这似乎有些随机。我缺少一些标准吗?

(另外,用 time() 播种 rand() 是不好的,然后用 rand() 播种 ISAAC?)

【问题讨论】:

  • 什么是随机?我的意思是,一切都是随机的,序列5555555555 是完全随机的,数字6 也是如此。
  • 它不必非常随机。该标准包括一个最小可接受的实现,它不是很随机的。不要忘记Dilbert's encounter with randomness
  • rand() 应该只是伪随机的一种非常弱的形式。它远不能保证是随机的。如果你真的需要一个真正的随机数,你也需要自己实现它。
  • 我明白“随机是一个模糊的概念”。但是,当我们可以在几次调用后轻松预测下一个数字时,我们是否同意该函数不是非常随机的?我倾向于制作游戏,当每一个障碍都在左边时,这很明显。所以,这个随机性的想法是有东西的。
  • @Orion 在非关键应用程序中使rand“更随机”的标准方法是在第一次使用之前调用srand。例如,臭名昭著的srand(time(NULL)); 可以在您的游戏中完成这项工作。

标签: c random


【解决方案1】:

它不仅不必是随机的,它不能是随机的,因为它必须是完全确定的:

§7.22.2.2/2:

srand 函数使用参数作为新的伪随机数序列的种子,这些伪随机数序列将由后续调用 rand 返回。如果随后使用相同的种子值调用 srand,则应重复伪随机数序列。如果在调用 srand 之前调用了 rand,则应生成与第一次调用 srand 时相同的序列,种子值为 1。

如果您需要真正的随机性——出于任何加密目的——在 Linux(和大多数其他 unice)上使用 /dev/random,在 Windows 上使用 CryptGenRandom

如果您对 伪随机 序列与随机序列的相似程度感兴趣,那就是statistically random,请参阅@Story Teller's answer

【讨论】:

    【解决方案2】:

    虽然 C 标准中的注释不是规范性的,但它确实这样说:

    7.22.2.1 The rand function / note 295

    对于生成的随机序列的质量没有任何保证,并且已知某些实现会生成具有令人痛苦的非随机低位比特的序列。具有特殊要求的应用程序应使用已知足以满足其需求的生成器。

    所以你是正确的,标准库的完全惰性实现看起来像这样。用time 播种rand 还不错,它和其他任何种子一样好,并且只要它只播种一次就可以提供一定程度的随机性。但我不会将rand 用于任何严肃的应用程序,正是因为缺乏保证。

    【讨论】:

    • 如果您将它用于加密密钥生成之类的事情,请使用经过实际验证的伪随机算法。
    • @Magisch,如果您使用它来生成加密密钥,请使用实际随机性。伪随机不适合任何和所有密码学应用程序。
    • @JanHudec 即使是最复杂的加密 KDF 仍然是伪随机的,不是吗?我一直认为真正的随机与计算机无关
    • @Magisch,操作系统确实提供了真正熵的来源。现代计算机通常有一个专门的来源,使用热噪声来生成它,因为 SSL 消耗了 很多 它。如果没有这些,操作系统会从外部事件(如按键、鼠标移动或网络数据包到达)的精细时间中收集熵。而且由于旧的窗口甚至没有这样做,一些密钥生成器会弹出一个窗口并要求您将鼠标移到它上面一段时间以收集一些真实的熵。
    • @Magisch,KDF 确实是伪随机的,但推导依赖于密码本身是随机选择的,密码的熵是加密可以依赖的所有熵——即破解密码就像猜密码一样困难。由于rand 不是 KDF,因此与讨论几乎无关。
    【解决方案3】:

    如 POSIX 中所述,它不必是随机的,而是伪随机的(可重现的和确定性的):

    rand() 函数应计算伪随机整数序列 在 [0, {RAND_MAX}] 范围内

    这个规范说它符合 ISO-C 标准。

    显然,您的实施提议并未提供伪随机序列。伪随机生成器的快速定义可能是:“提供均匀分布的生成器”,您的显然没有提供。你们的价值观彼此之间的相关性太微不足道了。

    【讨论】:

      猜你喜欢
      • 2013-04-23
      • 1970-01-01
      • 1970-01-01
      • 2012-03-31
      • 1970-01-01
      • 2012-04-18
      • 2021-09-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多