使用单个随机数发生器(RNG)生成多个数字与每个发生器生成一个数字并丢弃它之间是否存在差异?这两种实现都会产生同等随机的数字吗?普通RNG和安全RNG之间是否存在差异?

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

更新:此问题与随机序列的子集是否也是随机的?

有帮助吗?

解决方案

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

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

将随机数生成器视为混合数字集合,然后以随机顺序处理它们。种子用于“洗牌”。数字。一旦种子被设定,数字序列是固定的并且很难预测。有些种子会比其他种子更早重复。

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

当您为其提供单个种子时,生成器将生成类似随机的值,并让它生成值。如果更改种子,那么与上一个种子生成的值相比,使用新种子值生成的数字可能不会显示为随机 - 当您更改种子时,所有投注都将关闭。所以不要。

一种合理的方法是拥有一台发电机并“交易”。各种客户的数字。不要乱用创建和丢弃生成器。不要乱用变种。

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

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

其他提示

我建议多次使用一台发电机。据我所知,所有的发电机都有一个状态。种子生成器时,可以根据种子将其状态设置为某种状态。如果你继续产生新的种子,你选择的种子可能不会像使用一个生成器生成的数字一样随机。

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

基于硬件的真实[1]随机数生成器是可能的,但非平凡且通常具有较低的平均速率。可用性也是一个问题[2]。谷歌搜索“散粒噪音”或“放射性衰变”或“放射性衰变”。与“随机数发生器”组合使用应该返回一些点击。

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

正如其他人所说,软件系统只是伪随机的,必须维持状态。

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

这些是关于/ dev / random熵池的默认输入实际上是多么随机的一些论点。


脚注:

  1. 模拟我们对物理的理解的任何问题
  2. 因为您正在等待随机过程
  3. / dev / random功能可直接访问来自各种来源的熵池,这些来源被认为是真正的或几乎是随机的,并在熵耗尽时阻塞
  4. / dev / urandom就像/ dev / random,但当entopy耗尽时,会使用加密哈希,这使得熵池实际上是有状态的PRNG

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

创建单个RNG并从中抽取许多数字会好得多。

正如人们已经说过的那样,将PRNG播种一次并重新使用它会好得多。安全的PRNG只是适用于加密应用程序的PRNG。每次重播的唯一方法是给出合理随机的结果,它来自真正随机的“真实世界”。来源 - 即专门的硬件。即便如此,源可能存在偏差,理论上使用相同的PRNG仍然会更好。

正常情况下,为一个严重的PRNG播种一个新状态需要很长时间,而每次制作新状态实际上并没有多大帮助。 唯一可以想到你可能想要多个PRNG的情况是针对不同的系统,比如在赌场游戏中你有一个用于洗牌的发生器和一个单独的用于生成由计算机控制字符完成的评论,这种方式真的很专用用户无法根据角色行为猜测结果。

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

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

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

这可能听起来有点抽象,并没有完全回答你的问题,但我认为它仍然适用。从理论的角度来看,如果不涉及国家,就不可能使用RNG。无论如何,有一些技术可用于缓解这种交互并使其出现,好像整个操作都是无状态的。

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

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

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

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

嗯,只要它们每次创建时播种方式不同,那么不,我认为没有任何区别;然而,如果它取决于时间之类的东西,那么由于种子偏向,它们可能是不均匀的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top