【问题标题】:How does rand() work? Does it have certain tendencies? Is there something better to use?rand() 是如何工作的?有一定的倾向吗?有没有更好用的东西?
【发布时间】:2011-04-02 03:35:38
【问题描述】:

我已经读到它与时间有关,你也可以从包含 time.h 中得到,所以我假设了很多,但它是如何工作的呢?此外,它是否有任何奇数或偶数或类似的趋势?最后,在 C 标准库或 Foundation 框架中是否有更好的分布?

【问题讨论】:

  • “读过它与时间有关”?这通常是错误的。你觉得你读了什么?你能找到报价或参考吗?还。请阅读这个。 en.wikipedia.org/wiki/Pseudorandom_number_generator
  • 我怀疑这来自使用 srand(time(NULL)); 的 C / Unix 习惯用法,它使用自纪元 (man 2 time) 以来的当前时间(以秒为单位)为srand 播种。

标签: objective-c c random


【解决方案1】:

简述:

  • 您使用time.h 获取种子,这是一个初始随机数。然后 C 对该数字进行一系列操作以获得下一个随机数,然后对该数字进行操作以获得下一个随机数,然后......你得到了图片。

  • rand() 能够触及每一个可能的整数。无论输入种子如何,它都不会喜欢偶数或奇数,很高兴。尽管如此,它还是有局限性——它会相对快速地重复自己,并且几乎在每个实现中只给出最多 32767 的数字。

  • C 没有另一个内置的随机数生成器。如果你需要一个真正强大的包,网上有很多可用的包,但Mersenne Twister 算法可能是最受欢迎的选择。

现在,如果您对上述原因为什么感兴趣,下面是有关rand() 工作原理的血腥细节:

rand() 就是所谓的“linear congruential generator”。这意味着它采用了以下形式的方程:

xn+1 = (*a****xn + ***b*) mod m

其中 xn 是第 nth 个随机数,而 ab 是一些预定的整数。算术以 m 为模执行,m 通常为 232,具体取决于机器,因此在计算中只保留最低 32 位xn+1.

那么,在英语中,想法是这样的:要获得下一个随机数,将最后一个随机数乘以某个值,然后加上一个数字,然后取最后几个数字。

一些限制很快就会显现出来:

  • 首先,您需要一个起始随机数。这是您的随机数生成器的“种子”,也是您听说过使用time.h 的地方。由于我们想要一个真正的随机数,因此通常的做法是询问系统现在几点(以整数形式)并将其用作第一个“随机数”。此外,这也解释了为什么两次使用相同的种子会总是给出完全相同的随机数序列。这听起来很糟糕,但实际上很有用,因为当您控制程序的输入时,调试会容易得多

  • 其次,ab 必须非常、非常仔细地选择,否则你'会得到一些灾难性的结果。幸运的是,线性同余生成器的方程很简单,数学已经得到了一些详细的计算。事实证明,选择满足 *a***mod8 = 5 和 ***b* = 1 的 a 将确保所有 m 个整数的可能性相同,与种子的选择无关。您还需要一个非常大的 a 值,以便每次将它乘以 xn 时都会触发 a 模和斩波关闭很多数字,否则一行中的许多数字将只是彼此的倍数。因此,根据 Knuth 的说法,a 的两个常见值(例如)是 1566083941 和 1812433253。 GNU C 库恰好使用 a=1103515245 和 b=12345。 wikipedia page for LCGs 提供了许多实现的值列表。

  • 第三,线性同余生成器实际上会因为该模而重复自身。这将是一些非常令人兴奋的数学运算,但结果非常简单:在生成 m 个数字后,该序列将自行重复。在大多数情况下,这意味着您的随机数生成器将每 232 个周期重复一次。这听起来很多,但实际上并不适用于许多应用程序。如果您正在使用 Monte Carlo 模拟进行认真的数值工作,那么这个数字绝对不够。

  • 第四个不太明显的问题是这些数字实际上并不是真正随机的。他们有一种有趣的相关性。如果您从具有某个值为 a 的 LCG 中获取三个连续整数 (x, y, z) m,这三个点将总是落在三个点的所有线性组合(1,a, a2), (0, m, 0), (0, 0, m)。这就是著名的马萨利亚定理,如果你不明白,也没关系。这意味着:来自 LCG 的随机数的三元组将在某个深层次上显示相关性。通常它太深了,你或我都无法注意到,但它就在那里。如果给定第二个和第三个数字,甚至可以在三个数字的“随机”序列中重建第一个数字!这根本不适合密码学。

好在像rand() 这样的 LCG 占用空间非常非常小。它通常只需要 32 位来保留状态,这非常好。它也非常快,只需要很少的操作。这些使其适用于非关键嵌入式系统、视频游戏、休闲应用程序等。

PRNG 是一个引人入胜的话题。如果您渴望了解更多关于历史或当今各种实现的信息,Wikipedia 总是一个好去处。

【讨论】:

  • 对于 C,您所描述的只是rand 的一种可能实现。不同的 C 实现具有不同的 PRNG,一些较旧的 PRNG 即使用于非加密目的也可能非常糟糕。我不了解 Objective C,也许它确实需要一个特定的 RNG。
  • @Giles:真的吗?它们都使用 LCG,但根据 Nicholas J. Giordano 和 Hisao Nakanishi(第二版)的 Computational Physics 使用不同的系数。 rand() 的早期版本选择了非常差的系数。 RANDU 可能是您正在考虑的非常糟糕的实现。它在 LCG 被很好地理解之前就出现了,并且 ***a***=65539 ​​和 ***b***=0 带来了著名的灾难性结果。据我所知,在开发 C 时并没有真正可用的其他小型 PRNG。您认为还使用了哪些其他实现方式?
  • GCC 不“使用”任何rand() 的实现。 GCC 是一个编译器,rand( ) 由宿主系统的 libc 提供。 gnu libc 可以跨平台使用特定的实现。
【解决方案2】:

rand 返回由pseudo-random number generator (PRNG) 生成的数字。它返回的数字序列是确定性的,基于 PRNG 的初始化值(通过调用 srand)。

数字的分布应该使它们看起来有些随机,因此,例如,奇数和偶数应该以大致相同的频率返回。随机数生成器的实际实现未指定,因此实际行为是特定于实现的。

要记住的重要一点是rand 不返回随机数;它返回伪随机数,它返回的值由种子值和rand 被调用的次数决定。这种行为适用于许多用例,但不适用于其他用例(例如,rand 不适用于许多加密应用程序)。

【讨论】:

  • 数字如何变化与它被调用的次数有关?
  • 还有,它和arc4random()有什么区别?
  • @Regan:这取决于使用的PRNG,我不知道arc4random是什么。
  • “数字如何变化”?他们不会改变。它们是伪随机数。从给定的种子,它们产生相同的随机序列。你在问什么?
  • rand() 的每次调用都会返回一个新计算的伪随机值,并更新其内部状态(也称为种子)。调用srand() 允许您设置种子,以便您可以重复来自rand() 的相同值序列,这在调试时有时很有价值。 James 是说连续调用 rand() 返回的值序列是确定性的,并且取决于 srand() 设置的种子。
【解决方案3】:

rand() 是如何工作的?

http://en.wikipedia.org/wiki/Pseudorandom_number_generator

我已经读到它有一些东西 做时间,你也从 包括时间.h

rand() 与时间无关。但是,使用time() 来获取 PRNG 的“种子”是很常见的,这样每次运行程序时都会得到不同的“随机”数字。

还有,有没有什么倾向 对奇数或偶数或 类似的东西?

取决于使用的确切方法。 rand() 有一种流行的实现方式,它在奇数和偶数之间交替。因此,请避免编写像rand() % 2 这样依赖于最低位随机的代码。

【讨论】:

  • 你说的是seed+prime*steps实现吗?
猜你喜欢
  • 2016-07-22
  • 1970-01-01
  • 1970-01-01
  • 2015-06-27
  • 2010-10-09
  • 2012-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多