C++ 多次调用srand如何影响随机性的质量?

C++ 多次调用srand如何影响随机性的质量?,c++,random,srand,C++,Random,Srand,该条规定: srand(时间(0))我将把这一行作为main()中的第一行 相反,如果多次调用(,实际上会导致 随机数) …我把我有意见的那条线加粗了。。。在程序中重复一次常用建议以调用。像这样的问题需要重新迭代,因为time(0)以秒为单位返回当前时间,所以在同一秒内多次调用srand将产生相同的种子。一种常见的解决方法是使用毫秒或纳秒 然而,我不明白为什么这意味着srand应该或只能调用一次,或者它如何导致更少的随机数 : 一般来说,伪随机数生成器只应 在任何对rand()的调用和程序启动之

该条规定:

srand(时间(0))我将把这一行作为main()中的第一行
相反,如果多次调用(,实际上会导致
随机数

…我把我有意见的那条线加粗了。。。在程序中重复一次常用建议以调用。像这样的问题需要重新迭代,因为
time(0)
以秒为单位返回当前时间,所以在同一秒内多次调用
srand
将产生相同的种子。一种常见的解决方法是使用毫秒或纳秒

然而,我不明白为什么这意味着
srand
应该或只能调用一次,或者它如何导致更少的随机数

:

一般来说,伪随机数生成器只应 在任何对rand()的调用和程序启动之前,种子设定一次。 不应重复播种,也不应在每次希望生成新一批伪随机数时重新播种。

主席的答复:

一旦初始化,将生成具有种子值的初始状态 足够的随机数,因为您没有使用srand设置内部状态, 从而使数字更可能是随机的。


也许他们只是使用了不精确的语言,但这些解释似乎都无法解释为什么多次调用
srand
是不好的(除了生成相同的随机数序列),或者它如何影响数字的“随机性”。有人能帮我澄清一下吗?

伪随机发生器是一种产生看起来几乎是随机数字的引擎。然而,它们是完全确定的。换句话说,给定一个种子
x0
,它们是通过在
x0
上重复应用一些内射函数产生的,称之为
f(x0)
,因此
f^m(x0)
f^{m-1}(x0)
f^{m+1}(x0)
,是完全不同的,其中,符号
f^m
表示函数组合
m
次。换句话说,
f(x)
具有巨大的跳跃,几乎与之前的跳跃不相关

如果您在一秒钟内多次使用
sradnd(time)
,您可能会得到相同的种子,因为时钟没有您想象的那么快。所以产生的随机数序列是相同的。这可能是一个(巨大的)问题,尤其是在密码学应用中(无论如何,在后一种情况下,人们购买基于实时物理过程(如大气数据中的温差等)或最近测量量子位(如偏振光子的叠加)的好数字发生器,后者是真正随机的,只要量子力学是正确的。)

rand
还有其他严重问题。其中一个问题是分布有偏见。请参阅,例如,有关一些讨论,尽管我记得我在上面看到过类似的内容,但现在找不到

如果你打算在加密应用程序中使用它,就不要这样做。使用
和像Mersene's twister
std::mt19937这样的严肃随机引擎,结合
std::random\u设备

如果使用
srand
对随机数生成器进行两次种子设定,并获得不同的种子,则 您将得到两个完全不同的序列。这可能会让您满意。但是,由于我上面提到的问题,每个序列本身都不是一个好的随机分布。另一方面,如果您对rng进行过多次种子设定,您将获得相同的种子,这是不好的,因为您将一次又一次地生成相同的数字获得


PS:从评论中可以看出,伪数依赖于一个种子,这是不好的。这是伪数的定义,这不是一件坏事,因为它允许你用相同的序列重复数值实验。想法是每个不同的种子应该产生一个(几乎)的序列随机数,与之前的序列不同(从技术上讲,你不应该能够将它们与完美随机序列区分开来)。

从这个问题看
srand()
的来源:

此外,此线程的示例实现:

static unsigned long int next = 1;

int rand(void) // RAND_MAX assumed to be 32767
{
    next = next * 1103515245 + 12345;
    return (unsigned int)(next/65536) % 32768;
}

void srand(unsigned int seed)
{
    next = seed;
}
如您所见,当您调用
srand(时间(0))
时,您将在
rand()上获得新号码
取决于seed。数字在数百万之后会重复,但再次调用
srand
会使它成为另一个数字。无论如何,它必须在数个周期之后重复-但顺序取决于
srand
的参数。这就是为什么C rand不适合加密的原因-当您知道seed时,您可以预测下一个数字

如果你有快速循环,调用
srand
每次迭代都是毫无意义的-你可以得到相同的数字,而你的
time()
(对于现代CPU来说,1秒的时间是非常长的)给另一个种子

在简单的应用程序中没有理由多次调用srand-这个生成器在设计上很弱,如果你想要真正的随机数,你必须使用其他的(我知道最好的是Blum Blum Shub)


对我来说,没有多少随机数-它总是取决于种子,如果使用相同的种子,它们会重复。使用时间是一个很好的解决方案,因为它很容易实现,但您必须只使用一个(在
main()
)的开头,或者当您确定要调用
srand(时间(0))时
再过一秒钟。

种子决定将按顺序生成哪些随机数,即,
srand(1)
将始终在第一次调用
rand()
时生成相同的数,在第二次调用
rand()
时生成相同的数,依此类推

换句话说,如果在每次
rand()
调用之前使用相同的种子重新播种,那么每次都会生成相同的随机数

因此,在歌唱过程中,以
时间(0)
连续播种
int state; // persistent state

int rand() {
  state = (a * state + b) % c;
  return state;
}
a = 69069
b = 1
c = 2^32
1
69070
138139
207208
...