穷举随机数发生器

时间:2012-01-21 13:44:12

标签: algorithm random

在我的一个项目中,我遇到需要在给定范围内生成一组数字:

  
      
  • 详尽无遗,这意味着它将覆盖给定的大部分内容   范围没有任何重复。

  •   
  • 它将保证确定性(每次序列都是   相同)。这可以用固定的种子来实现。

  •   
  • 它将是随机的(我对随机数理论不是很精通,但我想有一堆描述随机性的规则。从0,1,2..N这个角度来看,它不是随机的)

  •   

我所说的范围可以是整数范围,也可以是实数范围。

例如,如果我使用标准C#随机生成器在范围[0,9]中生成10个数字,我会得到这个:

0 0 1 2 0 1 5 6 2 6  

正如你所看到的,给定范围的很大一部分仍然是“未开发的”并且有很多重复。

当然,输入空间可能非常大,因此记住以前选择的值不是一种选择。

解决这个问题的正确方法是什么?

感谢。

评论后: 好吧我同意随机不是正确的词,但我希望你明白我想要实现的目标。我想探索可能很大的给定范围,因此在内存列表中不是一个选项。如果范围是(0,10)并且我想要三个数字我想保证那些数字将是不同的并且它们将“描述范围”(即它们不会都在下半部分等)。

确定性部分意味着我想使用标准rng和固定种子之类的东西,所以我可以完全控制序列。

我希望我让事情更清楚一点。

感谢。

5 个答案:

答案 0 :(得分:4)

以下是三种不同权衡的选择:

  1. 提前生成一个数字列表,然后使用fisher-yates shuffle对其进行随机播放。根据需要从列表中选择。 O(n)总内存,每个元素的O(1)时间。随机性与您用来进行随机播放的PRNG一样好。这三种选择中最简单的一种。
  2. 使用Linear Feedback Shift Register,它会在重复之前生成一次序列中的每个值。 O(log n)总内存,每个元素的O(1)时间。然而,根据当前值很容易确定未来值,并且LFSR最容易构建为2个周期的功率(但您可以选择2的下一个最大功率,并跳过任何超出范围的值)。
  3. 使用secure permutation based on a block cipher。适用于2期的任何权力,并且有一点额外的诡计,任何任意的时期。 O(log n)总空间和每个元素的O(1)时间,随机性与分组密码一样好。三个中最复杂的实现。

答案 1 :(得分:3)

如果你只是需要什么,那么这样的事情呢?

maxint = 16
step = 7
sequence = 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9, 0

如果选择右步,它将在重复之前生成整个间隔。您可以使用不同的步骤值来获得“看起来”不错的东西。这里的“种子”是你从序列开始的地方。

这是随机的吗?当然不是。根据随机性的统计检验,它看起来是随机的吗?这可能取决于步骤,但可能这看起来根本不是统计随机的。但是,它肯定会选择范围内的数字,而不是原始顺序,并且没有记录到目前为止所选择的数字。

事实上,你可以通过列出一些因素来使这看起来更好 - 如[1,2,3,4,5],[6,7,8,9,10],[11,12, 13,14,15,16] - 并使用它们的混洗版本来计算step * factor(mod maxint)。假设我们改变了[3,2,4,5,1],[6,8,9,10,7],[13,16,12,11,14,15]等示例因子列表。然后我们得到序列

5, 14, 12, 3, 7, 10, 8, 15, 6, 1, 11, 0,  4, 13, 2, 9

因子列表的大小是完全可调的,因此您可以根据需要存储尽可能多的内存。更大的因子列表,更随机性。无论因素列表大小如何都不重复。当你耗尽一个因子列表时,生成一个新因子就像计算和改组一样容易。

答案 2 :(得分:1)

我的印象是,您所寻找的是一个随机排序的数字列表,而不是随机的数字列表。您应该能够使用以下伪代码获得此功能。更好的数学可能会告诉我这实际上是不是随机的:

list = [ 1 .. 100 ]
for item,index in list:
  location = random_integer_below(list.length - index)
  list.switch(index,location+index)

基本上,浏览列表并从列表的其余部分中选择一个随机项,以便在您所在的位置使用。这应该随机排列列表中的项目。如果你需要每次都重现相同的随机顺序,可以考虑保存数组,或者确保random_integer_below总是以给定种子的相同顺序返回数字。

答案 3 :(得分:0)

使用随机数生成器来选择范围内的数字。最终会发生的是你还有一个数字要填充,你的随机数发生器会反复循环,直到它选择那个数字。根据随机数生成器,无法保证将会发生。

您应该做的是生成所需范围内的数字列表,然后使用随机数生成器对列表进行随机播放。 shuffle被称为Fisher-Yates shuffle,或者有时被称为Knuth shuffle。这是伪代码,用于将n个元素的数组x混洗,索引从0到 n -1:

n -1到1的 i

j =随机整数,使得0≤ j i
交换 x [ i ]和 x [ j ]

答案 4 :(得分:0)

按顺序生成包含范围的数组。所以数组包含[0, 1, 2, 3, 4, 5, ... N]。然后使用Fisher-Yates Shuffle来加扰数组。然后,您可以遍历数组以获取随机数。

如果您需要重复性,请在随机播放开始时使用相同的值为随机数生成器播种。