【问题标题】:Will rand() sometimes return the same consecutively?rand() 有时会连续返回相同的值吗?
【发布时间】:2014-07-23 13:30:01
【问题描述】:

我只是好奇,单线程程序能否在两次连续调用rand() 时获得相同的返回值?

那么,这个断言会触发吗?

assert(rand() != rand());

【问题讨论】:

标签: c++ c visual-c++ random


【解决方案1】:

如果我们能找到一个例子,那么您的问题的答案是“是”。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
  unsigned int i;
  for(i = 0; ; i++) {
    int r = rand();
    if (r == rand()) {
        printf("Oops. rand() = %d; i = %d\n", r, i);
        break;
    }
  }
  return 0;
}

使用 Visual Studio 2010 在 Windows 上打印 Oops. rand() = 3482; i = 32187

编辑: 使用以下版本检测 2 个连续 rand() 调用返回相同值的所有序列。 C 仅指定 rand() 应返回“0 到 RAND_MAX" 和 RAND_MAX 至少应为 32767。 对 PRNG 的质量、其实现或其他细节(例如 2 个连续的 rand() 调用是否可以返回相同的值)没有任何限制。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
  unsigned int i;
  int r1 = rand();
  int r2 = rand();
  for(i = 0; ; i++) {
    if (r1 == r2) {
        printf("Oops. rand() = %d; i = %d\n", r1, i);
    }
    r1 = r2;
    r2 = rand();
  }
  return 0;
}

【讨论】:

  • @bits_international 因为它来得较晚,unwind 的回答是每个人的第一个冲动。
  • @bits_international:手册或标准中的定义比程序执行的结果更权威。就我们所知(未参考 rand() 的实际定义),此行为可能是 Visual Studio 实现中的错误,或者程序可能具有未定义的行为。
  • 只是一个挑剔,但看起来这可能会错过很多随机连续数字。它只检查奇数调用是否与下一个偶数调用相同,而不是偶数调用与下一个相同。你最终找到了一个,但很有可能还有一个更早的案例。
  • 在 Ubuntu 64 位 (amd64) 上,使用 gcc 4.6.3,rand() 将在 2888000745 次迭代后重复 1804289383。
  • @Mankarse:这个程序证明了 OP 问题的答案是“是”:OP 询问它是否会发生,这个答案证明它可以。 OP 没有询问标准是否允许这种行为。即使这是 MSVC 中的一个错误,它仍然会回答这个问题。 (当然,如果是,说明这是一个错误的答案也会很有用。)
【解决方案2】:

我做了我的研究

发现我的编译器 (msvc10) 的 rand 实现确实像其他 c/c++ 编译器一样使用线性同余生成器

线性同余生成器

线性同余生成器使用递归方法。

ptd->_holdrand(n) 永远不会等于 ptd->_holdrand(n+1),但 mod 结果会等于。

msvc 实现

@nos 显示结果

return( ((ptd->_holdrand = ptd->_holdrand * 214013L + 2531011L) >> 16) & 0x7fff );

ptd->_holdrand = 2375716238;
return 3482; (2375716238 >> 16) % 32768
ptd->_holdrand = 228240921;
return 3482; (228240921 >> 16) % 32768

最终的答案是 rand() 会像我的直觉一样多次返回相同的值。

【讨论】:

  • 很高兴您进行了研究,但这通常是 发布问题之前的步骤(stackoverflow 上几乎没有人遵守的规则)。
  • +1 用一些数学作为答案来补充您自己的问题。就像@Shahbaz 说的那样,最好在提出问题之前进行此类研究,以避免需要询问您是否找到了您正在寻找的东西,但是最好在 SO 上有这样的参考问题(在我看来)无论如何。
  • @ChrisCirefice,这是真的。最好的办法是:做研究(在这个过程中可能会发现 SO 中没有任何问题可以回答你)。如果您没有找到答案,请提出问题。如果您确实找到了答案,请无论如何提出问题并发布您的回复以帮助他人(您可以同时发布问题及其答案!)。为一个经过充分研究的问题(以及可能写得很好的答案)获得奖励。
  • 但通常答案会暗示要做什么研究,因此如果不阅读问题的答案,研究尝试就会失败。有时答案给出了一个不完整的答案,而提问者比其他人对完整答案更感兴趣,可以以此为起点。发布改进的答案对每个人都有好处。发布后进行研究比发布后没有研究要好得多。
  • @Shahbaz 我不同意。我认为如果一个问题可能会产生对其他用户有帮助的信息,那么发布它是可以的,只要它不是重复的。这绝对是这样一个问题。
【解决方案3】:

一个好的随机数生成器应该有时会连续两次返回相同的值。假设它返回正整数 0 不得到两个相同数字的机会大约是 10^15 分之一。

【讨论】:

  • 直到您将 randomize() 与 rand/random () 一起使用,对吧? randomize() 函数是一个单独的函数,我过去在我希望 random/rand() 返回一个纯随机数时使用它。同样,您仍有可能获得相同的 #,但这种情况很少见。
  • @ArunSangal 取决于你用它做什么,你用什么播种。
【解决方案4】:

一个理想的随机 rand() 函数,如果被调用两次,每次都会返回相同的结果,概率为 1.0 / RAND_MAX

rand() 不是真正的随机数生成器。它是 pseudorandom number generator (PRNG),通常是 linear congruential 类型。

PRNG的内部状态不能在连续调用中重复;如果是这样,rand() 将永远停留在同一个号码上。这可能发生在设计不佳的算法上,例如 middle square method

但是,某些(但不是全部)PRNG 实现在其内部状态中的位比在其输出中的位多。例如,java.util.Random 使用 48 位内部状态,但在其输出中仅包含最高有效 32 位。在这种情况下,(至少理论上)可以连续两次获得相同的输出,而不会具有相同的内部状态。

【讨论】:

    猜你喜欢
    • 2018-03-12
    • 1970-01-01
    • 1970-01-01
    • 2021-03-20
    • 2017-07-03
    • 1970-01-01
    • 1970-01-01
    • 2022-12-12
    相关资源
    最近更新 更多