【问题标题】:Improving "randomness" when extending the range of rand()扩展 rand() 的范围时提高“随机性”
【发布时间】:2014-06-24 18:54:13
【问题描述】:

我正在使用我在其他 SO 帖子中找到的一对算法(在下面的参考资料中列出),并试图找出如何改进分布。我通过将位数加倍来有效地扩展随机数的范围,并希望确保分布尽可能均匀,同时消除(或至少减少)混洗算法的模偏差和其他伪影的影响那将使用我修改后的随机数生成器的结果。

因此,据我了解,如果我使用常量种子(即:srand(1))初始化我的 RNG,我将通过在 for 循环中调用 rand() 获得相同模式的确定性输出。现在,如果我要通过srand(time(NULL)) 初始化我的种子,这将是一个不同的模式,但它仍然可能无法帮助我解决以下问题:我正在尝试弄清楚我是否要实现以下算法:

  • 取两个随机数 a,b
  • 计算 a*(RAND_MAX+1)+b

我可以:

  1. 生成每个可能的坐标对 (a,b),其中 a,b ∈ Z+ on [0, RAND_MAX]ab 是介于零和 RAND_MAX 之间的正整数)。
  2. 最大限度地提高整个分布的均匀性(即:最佳平坦直方图)。

虽然rand() 的输出应该是均匀分布的,但我不知道它是否保证给我 N,N+1 调用的值以对每个循环进行 rand 每个循环并给我每对列出的点 (1 ) 在随机序列再次重复之前。 我的新随机数生成器理论上可以在[0, RAND_MAX ^ 2] 上生成随机值,但我不知道在这个范围内是否可能存在我的算法永远无法生成的“洞”,即值。

我自己试图进一步解决这个问题,但我找不到有关在 C 中生成的随机序列 rand() 会持续多长时间直到它重复自身的信息。由于缺少这些信息和其他信息,我无法确定是否可以生成每一对 (a,b)。

那么,使用rand(),是否有可能达到第(1)点,如果可以,是否有关于如何根据第(2)点优化其“随机性”的可靠建议?

感谢您的时间和帮助。

更新

我后来重新审视了这个问题,并使用 8 位 PRNG 对其进行了模拟。虽然它确实可以生成所有可能的坐标对,但分布实际上非常有趣,而且绝对不均匀。最后,我阅读了几篇关于 PRNG 的文章/论文,并使用 Mersenne Twiser 算法生成所需的额外位(即 MT19937-64)。

参考文献


  1. 扩展 rand() 最大范围,于 2014 年 5 月 7 日访问,<https://stackoverflow.com/questions/9775313/extend-rand-max-range>
  2. C 中的随机数组,于 2014 年 5 月 7 日访问,<https://stackoverflow.com/questions/6127503/shuffle-array-in-c>

【问题讨论】:

  • 虽然我通常很欣赏编辑,但我更喜欢不删除引用,因为我希望它们保持 IEEE 格式,这样如果问题是逐字复制/粘贴,则学分是人类可读的格式。另外,我认为他们应该尽可能在场。
  • Information on how long a random sequence generated -> 取决于 RNG。对于梅森捻线机,the period is 2^19937-1。默认实现看起来像是一个 LCG,这肯定不是那么好。
  • 一定要使用rand()吗?它的属性是依赖于实现的,正如您所注意到的,不能保证非常好。
  • 关于链接的讨论属于 Meta,所以我在那里发布了一个问题 (meta.stackoverflow.com/questions/253976/…)。 (我的个人观点或许可以从我对这个问题的表述中推断出来。)
  • “我的新随机数生成器...在 [0, RAND_MAX ^ 2] 上生成随机值”不正确。它可能在区间 `[0, ((RAND_MAX + 1) ^ 2 - 1)] 上生成。

标签: c algorithm random statistics


【解决方案1】:

假设

正如 cmets 中所指出的,rand() 的行为取决于实现。所以,让我们做一些简化的假设来解决问题:

  • rand() 可以生成从0RAND_MAX 的所有值。 理由:如果不能,则更难生成所有可能的对(ab)。
  • rand() 生成统计随机序列。 理由:组合两个随机函数(或相同的两次)的结果仅与基本随机函数一样好。

当然,我们不应该期望结果比构建块更好,因此rand() 实现中的任何缺陷都会反映在由它组成的任何函数中。

分布中的漏洞

播种rand() 为给定种子生成确定性序列,因为种子决定了 PRNG 的初始状态。序列的最大周期为 2N,其中 N 是状态中的位数。请注意,状态实际上可能比RAND_MAX 有更多的位,我们将假设RAND_MAX = (2N - 1) 对于本节。因为是序列,所以生成两个连续的“随机”N位值a和b意味着ab时间>。所以a*(RAND_MAX+ 1)+b这个方法会有一些漏洞。

关于 ab 的一点解释:PRNGs 通过维持 N 位的内部状态来工作。它唯一地使用该状态来确定其下一个状态,因此一旦相同的状态再次出现,序列就会开始重复。在序列开始重复之前经历的状态数称为周期。因此,从技术上讲,我们可以有 a = b,但这意味着周期为 1,即very bad PRNG。如需更多信息,请在软件工程网站上发布helpful answer on PRNG periods

没有漏洞的算法

允许连续“随机”调用相等的一种方法是生成 2 个 N 位数字,但只考虑一定数量的有效位,即丢弃一些。现在,我们可以有 a = b,尽管 very 的概率略低于另一个随机数 c。请注意,这类似于Java's random number generator 的工作方式。它以 48 位为种子,但输出 32 位随机数,丢弃 16 位(假设种子中的位数 = 状态中的位数)。

但是,由于您需要大于RAND_MAX 的值,因此您可以使用上述方法,然后将位连接起来,直到获得足够的位以达到所需的最大值(尽管如此,分布并不完全制服)。

【讨论】:

  • 您的答案的问题是,如果我是 BOFH 转为库的实现者,我可以轻松设计一个符合您的标准(仔细阅读)但在使用时显然是非随机的 rand()你描述的方式。 RANDU 不谈,标准实现不太可能这么差,但如果以可移植性为目标,为什么要冒险呢?
  • @DavidEisenstat 我已经编辑了我的假设以解决您的第一个问题。为了解决您的第二个问题:如果可移植性是一个目标,那么您首先不会使用rand(),因为它依赖于实现,因此根据定义不可移植。
  • 谢谢@DPenner,这解决了我的担忧,并回答了关于漏洞的担忧。对于我的最终实现,我可能会找到一个免版税的实现,例如 Mersenne Twister(我认为它是免版税的)。我很好奇a≠b。 PRNG不应该允许序列中连续重复的数字吗?我认为我最初方法的最大缺陷是无法保证每个 (a,b) 对都存在于我的序列中。
  • 我添加了关于 a ≠ b 的解释。请注意,它仅在 RAND_MAX = (2^N - 1) 的假设下成立,如果输出的位数少于内部状态维持的位数,则可以有连续的重复数字。
  • Nitpick:我认为您应该更清楚地区分种子(例如 srand)和内部状态。它们不需要具有相同的位数。
猜你喜欢
  • 2012-04-04
  • 1970-01-01
  • 2010-09-13
  • 2019-05-18
  • 2022-08-24
  • 1970-01-01
  • 2012-04-28
  • 2021-07-20
  • 1970-01-01
相关资源
最近更新 更多