我有一个非常大的范围/数字组(1..1236401668096)
,我基本上想要“洗牌”,即随机遍历而不重新访问相同的数字。我将运行一个Web服务,每次请求进入时它都会递增一个计数器并从该范围中拉出下一个“洗牌”号码。该算法必须适应服务器脱机,能够使用计数器的持久值重新启动遍历(类似于如何为伪随机数生成器播种,并获得相同的伪随机数给定种子和你正在进行哪次迭代。)
我想知道这种算法是否存在或是否可行。我见过Fisher-Yates Shuffle,但第一步是“记下从1到N的数字”,这将占用整个范围的TB级存储空间。为每个请求生成一个伪随机数可能会有一段时间,但随着数据库/树变满,碰撞将变得更加普遍并且可能降低性能(根据我的计算,在10亿次点击后已经有0.08%的碰撞几率)。对于我的场景,是否有更理想的解决方案,或者这只是一个梦想?
改组的原因是能够正确猜测序列中的下一个数字可能会导致我的应用程序中出现轻微的DOS漏洞,但也因为表示层看起来更好,分布更广(I' d而不是详细了解应用程序的 。此时我正在考虑使用PRNG并处理冲突或混洗范围切片(从(1..10000000).to_a.shuffle
开始,然后是(10000001, 20000000).to_a.shuffle
等,因为每个范围的数字都开始耗尽。)
那里的任何数学家都有更好的想法/建议吗?
答案 0 :(得分:1)
分而治之?分解成可管理的块并将它们洗牌。你可以划分数字范围,例如以它们的模数为模。该列表是建设性的,非常小,具体取决于n。一旦用尽,您可以使用下一个。
例如,如果您选择n为1000,则可以创建1000个不同的组。选择一个介于1和1000之间的随机数(让我们称之为x),然后将模数为1000的数字等于x。一旦耗尽了该范围,就可以选择1到1000之间的新随机数(显然没有x)以使下一个子集进行随机播放。跟踪已经使用了1..1000范围的数量应该不是一个挑战,所以你只需要一个可重复的shuffle算法来计算子集中的数字(例如Fisher-Yates的“指数”) “)。
答案 1 :(得分:1)
/dev/random
位有几种算法可以生成具有任意大且已知周期的伪随机数。两个明显的候选者是LCPRNG(LCG)和LFSR,但有更多的算法,如Mersenne Twister。
这些发电机的周期可以很容易地构造,以满足您的要求,然后您就不会发生碰撞。
您可以通过从/dev/random.
这样的界面添加10,20或30位加密散列熵来处理PRNG和LFSR的可预测行为。因为已知数字的确定性部分是唯一的如果你重复它的实际随机部分没有区别。
答案 2 :(得分:0)