我知道如何实现它。但是,我想了解 rand 在内部的行为方式以及为什么有必要为 rand 函数初始化“种子”值。
或者说——rand 函数如何使用种子值来生成随机数?
我知道如何实现它。但是,我想了解 rand 在内部的行为方式以及为什么有必要为 rand 函数初始化“种子”值。
或者说——rand 函数如何使用种子值来生成随机数?
有关更详细的说明,请参阅Wikipedia 。
线性同余生成器 (LCG) 代表了最古老和最著名的伪随机数生成器算法之一。 [1] 它们背后的理论很容易理解,并且易于实现且速度快。
生成器由递归关系定义:
X_{n+1} = ( a * X_n + c ) mod m
确切的实现细节取决于实现者。但是 GNU 实现(glibc)像这样实现 rand():http: //sourceware.org/git/ ?p=glibc.git;a=blob;f=stdlib/random_r.c;hb=glibc-2.15#l361
评论很好地解释了它。
/* If we are using the trivial TYPE_0 R.N.G., just do the old linear
congruential bit. Otherwise, we do our fancy trinomial stuff,
which is the same in all the other cases due to all the global
variables that have been set up. The basic operation is to add
the number at the rear pointer into the one at the front
pointer. Then both pointers are advanced to the next location
cyclically in the table. The value returned is the sum generated,
reduced to 31 bits by throwing away the "least random" low bit.
Note: The code takes advantage of the fact that both the front and
rear pointers can't wrap on the same call by not testing the rear
pointer if the front one has wrapped. Returns a 31-bit random number. */
关于您为什么总是需要种子值的问题:计算机科学中没有真正的随机数。计算机(在计算理论中)是完全确定性的机器。他们无法执行任何操作,其结果取决于机会。
只有伪随机数生成器可以生成看起来随机的数字流,但它们仍然是确定性计算的结果。这就是您需要种子值的原因:每个种子产生不同的数字序列。当你使用相同的种子时,你会得到相同的伪随机数序列。
可以利用 RNG 在获得相同种子时始终返回相同序列的行为:例如,经典的空间模拟Elite能够将具有数百个行星的巨大宇宙存储在一个整数中。它是怎么做到的?整个宇宙是随机生成的。重新创建 Universe 所需的所有数据都是种子值,这总是导致生成完全相同的 Universe。
大多数rand
实现都是LCG,它使用基本数学来执行混合。像大多数 PRNG 一样,它需要随机种子部分消除其通过使用固定和可预测的数学函数创建的确定性性质(这有好有坏,取决于它的预期用途)。
如果您对rand()
在实践中使用哪些算法来实现感兴趣, C 的 rand() 使用了哪些常用算法?可能会感兴趣。glibc 的实现以及一些解释其他算法的文章的链接。
至于为什么必须设置种子的问题,种子是防止随机数生成器每次都产生相同的数字序列的原因。由于没有真正的随机数生成器,如果你调用5 次srand(constant)
,rand()
你得到的 5 个“随机”数总是相同的。但是,如果您使用每次rand()
使用不同的值进行播种(默认值是我认为自 Unix 纪元以来的秒数),那么您将不会遇到此问题。