rand() 有时会连续返回相同的值吗?
Posted
技术标签:
【中文标题】rand() 有时会连续返回相同的值吗?【英文标题】:Will rand() sometimes return the same consecutively? 【发布时间】:2014-07-23 13:30:01 【问题描述】:我只是好奇,单线程程序能否在两次连续调用rand()
时获得相同的返回值?
那么,这个断言会触发吗?
assert(rand() != rand());
【问题讨论】:
当然。为什么不呢? 看看***.com/q/21634465/3235496 (这是一个java问题,但提出了有效的观点)。 你可以掷两次骰子,每次得到六次,不是吗? 只返回唯一数字是一种模式,而不是随机。 dilbert.com/strips/comic/2001-10-25 【参考方案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() 会像我的直觉一样多次返回相同的值。
【讨论】:
很高兴您进行了研究,但这通常是 发布问题之前的步骤(*** 上几乎没有人遵守的规则)。 +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 位。在这种情况下,(至少理论上)可以连续两次获得相同的输出,而不会具有相同的内部状态。
【讨论】:
以上是关于rand() 有时会连续返回相同的值吗?的主要内容,如果未能解决你的问题,请参考以下文章