19

使用单个随机数生成器 (RNG) 生成多个数字与每个生成器生成一个数字并丢弃它之间有区别吗?两种实现都生成同样随机的数字吗?正常的 RNG 和安全的 RNG 之间有区别吗?

我有一个 Web 应用程序,它应该代表客户生成一个随机数列表。也就是说,从每个客户的角度来看,这些数字应该是随机的。这是否意味着我需要为每个客户端会话保留一个单独的随机 RNG?或者我可以在所有会话中共享一个 RNG 吗?或者我可以根据每个请求创建和丢弃 RNG 吗?

更新:这个问题与随机序列的子集是否也是随机的有关?

4

10 回答 10

22

随机数生成器有一个状态——这实际上是一个必要的特性。下一个“随机”数字是前一个数字和种子/状态的函数。纯粹主义者称它们为伪随机数发生器。这些数字将通过随机性的统计测试,但实际上并不是随机的。

随机值的序列是有限的并且会重复。

将随机数生成器想象为对一组数字进行混洗,然后以随机顺序处理它们。种子用于“洗牌”数字。一旦设置了种子,数字序列就固定了,很难预测。有些种子会比其他种子更快地重复。

大多数生成器的周期足够长,没有人会注意到它重复。一个 48 位随机数生成器将在重复之前产生数千亿个随机数——使用 (AFAIK) 任何 32 位种子值。

当你给它一个种子并让它喷出值时,生成器只会生成类似随机的值如果您更改种子,则使用新种子值生成的数字与前一个种子生成的值相比可能不是随机的——当您更改种子时,所有赌注都已关闭。所以不要。

一种合理的方法是拥有一个生成器并将数字“处理”给您的各种客户。不要混淆创建和丢弃生成器。不要乱换种子。

最重要的是,永远不要尝试编写自己的随机数生成器。大多数语言库中的内置生成器都非常好。尤其是使用超过 32 位的现代版本。

一些 Linux 发行版有一个/dev/random/dev/urandom设备。您可以阅读这些内容来为您的应用程序的随机数生成器提供种子。这些具有或多或少的随机值,但它们通过从随机系统事件中“收集噪声”来工作。谨慎使用它们,因此在使用之间会有很多随机事件。

于 2008-10-15T03:37:39.650 回答
12

我建议多次使用单个生成器。据我所知,所有的发电机都有一个状态。当您为生成器播种时,您将其状态设置为基于种子的某些内容。如果您不断产生新的种子,您选择的种子很可能不会像仅使用一个生成器生成的数字那样随机。

对于我使用过的大多数生成器来说尤其如此,它们使用当前时间(以毫秒为单位)作为种子。

于 2008-10-15T01:04:52.033 回答
11

基于硬件的、真正的 [1] 随机数生成器是可能的,但不是微不足道的,而且通常具有较低的平均速率。可用性也可能是一个问题[2]。结合“随机数发生器”搜索“散粒噪声”或“放射性衰变”应该会返回一些命中。

这些系统不需要维护状态。可能不是你要找的。

正如其他人所指出的,软件系统只是伪随机的,并且必须保持状态。

一种折衷方案是使用基于硬件的 RNG 来提供熵池(存储状态),该池可用于播种 PRNG。这在 /dev/random [3] 和 /dev/urandom [4] 的 linux 实现中非常明确地完成。

这些是关于 /dev/random 熵池的默认输入到底有多随机的一些争论。


脚注:

  1. 以我们对物理学的理解的任何问题为模
  2. 因为你在等待一个随机的过程
  3. /dev/random 具有直接访问从被认为是真正或几乎随机的各种来源播种的熵池的功能,并在熵耗尽时阻塞
  4. /dev/urandom 类似于 /dev/random,但是当熵耗尽时,使用加密哈希,这使得熵池有效地成为有状态的 PRNG
于 2008-10-15T15:30:51.207 回答
5

如果您创建一个 RNG 并从中生成一个随机数,然后丢弃该 RNG,则生成的数字仅与用于启动 RNG 的种子一样随机。

最好创建一个 RNG 并从中提取许多数字。

于 2008-10-15T01:06:57.783 回答
2

正如人们已经说过的,最好将 PRNG 播种一次,然后重复使用它。安全 PRNG 只是一种适用于加密应用程序的 PRNG。每次重新播种都会产生合理随机结果的唯一方法是它来自真正随机的“现实世界”来源 - 即专用硬件。即使这样,来源也可能有偏差,理论上使用相同的 PRNG 仍然会更好。

于 2008-10-15T01:21:12.653 回答
2

通常,对于严重的 PRNG,播种新状态需要相当长的时间,并且每次都创建新状态并没有太大帮助。我能想到的唯一情况是您可能需要多个 PRNG 用于不同的系统,例如在赌场游戏中,您有一个用于洗牌的生成器和一个用于生成由计算机控制角色完成的评论的单独的生成器,这种方式真的很专注用户无法根据角色行为猜测结果。

播种的一个很好的解决方案是使用这个(Random.org),它们免费提供从大气噪声生成的随机数。它可能是比使用时间更好的播种来源。

编辑:在你的情况下,我肯定会为每个客户端使用一个 PRNG,如果没有其他原因,只是为了良好的编程标准。无论如何,如果您在客户之间共享一个 PRNG,您仍然会为每个客户提供伪随机值,其质量等于您的 PRNG 的质量。所以这是一个可行的选择,但似乎是一个糟糕的编程策略

于 2008-10-15T01:32:06.173 回答
1

值得一提的是,Haskell 是一种试图完全消除可变状态的语言。为了使这一目标与 IO 等硬性要求(需要某种形式的可变性)相协调,必须使用 monad 将状态从一个计算线程化到下一个计算。通过这种方式,Haskell 实现了它的伪随机数生成器。严格来说,生成随机数本质上是有状态的操作,但是 Haskell 能够通过将状态“突变”移动到 bind( >>=) 操作中来隐藏这个事实。

这可能听起来有点抽象,并不能真正完全回答您的问题,但我认为它仍然适用。从理论上讲,在不涉及状态的情况下使用 RNG 是不可能的。无论如何,有一些技术可以用来减轻这种交互并使其看起来好像整个操作是无状态的。

于 2008-10-15T06:00:14.230 回答
0

通常最好创建一个 PRNG 并从中提取多个值。创建多个实例意味着您需要确保实例的种子是唯一的,这需要合并特定于实例的信息。

顺便说一句,有更好的“真实”随机数发生器,但它们通常需要专门的硬件来执行诸如从计算机内部的电信号变化中获取随机数据之类的事情。除非你真的很担心,否则我想说语言库和/或操作系统中内置的伪随机数生成器可能就足够了,只要你的种子值不容易预测。

于 2008-10-15T01:14:24.947 回答
0

安全 PRNG 的使用取决于您的应用程序。随机数有什么用?如果它们是真正有价值的东西(例如任何与密码相关的东西),你就不想使用更少的东西。

安全 PRNG 速度要慢得多,并且可能需要库进行任意精度的操作,以及素数测试等......

于 2009-01-22T00:39:36.027 回答
-2

好吧,只要每次创建它们的种子都不同,那么不,我认为不会有任何区别;但是,如果它取决于时间之类的东西,那么由于种子有偏差,它们可能会不一致。

于 2008-10-15T01:04:42.767 回答