【问题标题】:Non-repeating PRNG algorithm非重复 PRNG 算法
【发布时间】:2017-03-04 06:44:57
【问题描述】:

以下算法生成一个不重复的随机数数组(示例是用 Fortran 95 编写的):

program test
implicit none

real :: x
integer :: i, aux
integer, dimension(100) :: y = 0

do i=2,100
  call RANDOM_NUMBER(x)
  aux = int(3 * x) + 1 ! random number: 1, 2 or 3
  aux = aux + y(i-1) ! adding previous selected number
  y(i) = MOD(aux,4) ! mod 4 gives the final result: 0, 1, 2 or 3
  print*, y(i)
enddo

end program test

在另一个论坛上,一位成员提出了该算法,以解决如何使用常规随机数生成器和每个循环固定数量的操作(例如,当随机值循环与前一个相同,不会给出每个循环的恒定操作数)。

他的算法似乎运行良好,结果是均匀分布的,并且在输出中 any 的任何子字符串中都没有明显的模式(我搜索了大小为 2 到 5 的子字符串,并且所有行为都符合预期)。但是这个解决方案让我感到困惑的是,随机数生成器只输出三个可能的数字(0、1 或 2),而整个算法却输出了四个可能的结果(0、1、2 或 3)。这怎么可能?我认为可以映射 PRNG 的结果,但不能映射它(例如,如果 PRNG 产生 0 到 7 之间的数字,它们可以映射为 0-3 => 0 和 4-7 =>1,但是只产生 0 和 1 的 PRNG 不能在同一循环中产生 0-7 之间的结果 - 因为显然可以将三个结果分组以映射 000 => 0, 001 => 1, .. . 111 => 7).


编辑:这是相同的算法,但用伪代码编写,因为这个问题与 Fortran 或任何编程语言无关

x ← 0
do
  aux ← random number between 1 and 3
  aux ← aux + x
  x ← aux MOD 4
  print x
enddo

【问题讨论】:

    标签: random mapping


    【解决方案1】:

    好吧,我可能遗漏了一些东西,因为我不完全记得 Fortran。

    为什么当 i = 1 时允许访问 y(i-1)。这不是违反数组边界吗?我会假设它只是返回零或其他东西。

    第一次通过循环时,aux 最终将是 1、2 或 3,假设 y(i-1) = 0,并且 y(1) 将相同(1、2 或 3)。然后第二次通过, aux 将是 (1, 2 or 3) + (1, 2 or 3) 这将是 2, 3, 4, 5 或 6 并且 y(2) 将是 0, 1, 2 或 3 ,因为 4 MOD 4 = 0 和 5 MOD 4 = 1。从那里开始,y(n) 可以是 0、1、2 或 3,因为您将始终将 (1、2 或 3) 添加到 (0 , 1, 2 or 3) 和 4 修改。

    我感觉你在做一个我没有做的假设,我看不出有什么有效的假设会将输出限制为只有 3 个值。

    RANDOM_NUMBER 函数分配0 <= x < 1。我不清楚您为什么要考虑数字的二进制表示,因为您似乎没有使用按位运算符。

    编辑: 这更有意义。我不明白你主要关注的是数字的分布,从统计学上讲。如果我对学术界有很多记忆,我可能可以用数字系列或一些统计符号更好地解释我对这个主题的想法,但就像我在大学里做任何事情来避免代数的摔跤室室友一样,我只会映射用一堆经验数字来表达我的想法:

    第一次循环,你会得到以下可能的值:(平凡的情况)

    aux:可以是 1、2 或 3

    y(i-1): 0

    辅助 + y(i-1):1、2 或 3

    y(i):1、2 或 3

    现在第二次通过,你实际上必须处理由获得每个可能结果的概率引起的权重:

    辅助:1、2 或 3

    y(i-1): 1、2 或 3

    aux + y(i-1): {aux 和 y(i-1) 的每个组合的总和} 1 2 3 3 4 4 4 5 5 6 {表示有 1/10 的机会获得1, 2 相同, 6 相同, 1/5 的机会得到 3, 相同的 5, 3/10 的机会得到 4;这不是一个非常均匀的分布}

    y(i) = 0 0 0 1 1 1 2 2 3 3 {原理相同,这个“输出”的分布更均匀}

    第三次通过

    辅助:1、2 或 3

    y(i-1): 0 0 0 1 1 2 2 3 3

    aux + y(i-1): {排序后} 1 1 1 2 2 2 2 2 3 3 3 3 3 3 3 4 4 4 4 4 4 5 5 5 5 6 6

    y(i): {排序后} 0 0 0 0 0 0 1 1 1 1 1 1 1 2 2 2 2 2 2 2 3 3 3 3 3 3 3

    平衡 a) 假设这种均衡趋势将继续用于值分布的风险 b) 避免计算这些样本值的日益复杂的愿望,推断分布将在某种程度上均匀似乎是合理的成长中的我。

    向自己证明这一点的最佳方法是更改​​算法以保留每次迭代的可能结果数组和输出概率,而不是随机数。我会把它留给你作为练习。

    我怀疑aux - y(i-1) 的可能值范围不是 MOD 右手操作数的倍数而导致的错误被 MOD 的散列性质所抵消。我的意思是,我认为概率的不平衡性分布在滑动窗口中的可能值范围内,或者更可能是旋转窗口,在 y(i) 的值范围内,从一次迭代到下一次迭代。希望你明白我的意思。

    【讨论】:

    • 关于您的替代算法,我建议您可以通过添加像 01100 这样的二进制值(确切值仅用于可视化)这样的操作,在达到 100 个样本之前使随机性偏差变得可以忽略不计每次迭代都向右旋转,到像 10110 这样的二进制值,每次迭代都会切换位,到像 11001 这样的二进制值,每次迭代都会向左旋转。然后您可以添加反馈,例如 y(i-1) 和可能的 y(i-5),可能带有系数,然后是 MOD。我认为伪对称和复杂性应该均匀分布。
    • 你可能想要一个种子值,它基于以开尔文为单位的时间或温度乘以年初至今的甲骨文股票易手数量,至少最初是这样,并且可能也加入到算法中。我可能没有明确表示每次迭代都将包含您的随机 0 或 1 值。我是不是对这个虚构的算法太过分了,而你想要的只是对一个不太复杂的算法投赞成票还是反对票?
    • 我已经给出了一个例子,如果我们有一个随机整数生成器输出 0 和 1,那么仅使用 sum 和 modulo 运算符将这个结果映射到假设为 0 的范围内是完全不可能的-99。如果这是正确的,那么我想知道为什么将 0 到 2 之间的值映射到 0 到 3 之间的值确实有效。如果我之前写的不正确,那么我很好奇这将如何工作,如何在每个周期产生比原来更多的“信息”。这有意义吗?
    • “错误”是一个糟糕的词选择,因为它在计算机科学和统计学中意味着完全不同的东西。我的意思只是“偏离统计随机性”,意思是“统计错误”或“干扰”。我想我理解你。我坚持我的回答的相关性。与下采样相反,您担心上采样的固有不准确性是否不正确,因为您试图在缺少精度的地方插入精度,而不是删除精度?我相信使用 MOD 进行散列可以消除这种担忧。
    • 不客气。我学到了一些东西。做你认为适合stackoverflow的事情。
    【解决方案2】:

    乍一看,上面的算法似乎将02之间的随机整数(即3个值)作为输入,并输出03之间的随机整数(即4个值)每个周期,由于上采样,这似乎是有问题的。但实际上该算法总是只在 3 个选项中进行选择,因为每个值不能与前一个值相同。例如,如果选择的第一个随机整数是0,则下一个整数有三个可能的值(123),这正是 PRGN 提供的范围。所以关键是要意识到 3 个随机值被映射为 4 个非重复随机值,并且可以做到这一点而不会产生任何不需要的模式。

    因此,将MOD N+1 用于从0N 的随机输入没有问题,因为信息量不会随之改变。但是当我们使用MOD N+2 或更大时,我们实际上确实观察到了如果输出是真正随机的则不应该存在的模式。例如,两个连续数字的某些序列永远不会出现:例如采用N = 3(即在02 之间输入)和MOD 5,将永远不会看到0 后跟4,因为没有输入使得表达式((input + 1) + 0) MOD 5 = 4 是真的。

    【讨论】:

      猜你喜欢
      • 2020-05-11
      • 2014-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-30
      • 1970-01-01
      • 2017-11-01
      • 1970-01-01
      相关资源
      最近更新 更多