一尘不染

使用PRNG而非改组生成改组范围

algorithm

给定一个任意的种子值,是否有任何已知的算法可以在线性时间和恒定空间(当输出迭代产生时)中产生一个改组范围[0..n]?

假设n可能很大,例如数以百万计,那么就不需要潜在地产生每个可能的排列,尤其是因为它是不可行的(种子值空间将需要很大)。这也是需要恒定空间的原因。(因此,我并不是特别在寻找数组改组算法,因为这要求将范围存储在长度为n的数组中,因此会使用线性空间。)

我知道问题162606,但是它没有提供对此特定问题的答案-从置换索引到该问题中给出的置换的映射将需要巨大的种子值空间。

理想情况下,它将像LCG一样工作,周期和范围为n,但是选择LCGa和选择cLCG的技巧很微妙。简单地满足LCG 的限制ac在整个周期内都可以满足我的要求,但是我想知道是否还有更好的想法。


阅读 233

收藏
2020-07-28

共1个答案

一尘不染

基于Jason的回答,我已经用C#实现了一个简单直接的实现。找到大于N的2的下一个最大幂。这使得生成a和c变得微不足道,因为c需要是相对质数的(意味着它不能被2整除,也就是奇数),而(a-1)需要可以被2整除,而(a-1)需要被4整除。从统计上讲,它需要1-2个全等才能生成下一个数字(因为2N>
= M> = N)。

class Program
{
    IEnumerable<int> GenerateSequence(int N)
    {
        Random r = new Random();
        int M = NextLargestPowerOfTwo(N);
        int c = r.Next(M / 2) * 2 + 1; // make c any odd number between 0 and M
        int a = r.Next(M / 4) * 4 + 1; // M = 2^m, so make (a-1) divisible by all prime factors, and 4

        int start = r.Next(M);
        int x = start;
        do
        {
            x = (a * x + c) % M;
            if (x < N)
                yield return x;
        } while (x != start);
    }

    int NextLargestPowerOfTwo(int n)
    {
        n |= (n >> 1);
        n |= (n >> 2);
        n |= (n >> 4);
        n |= (n >> 8);
        n |= (n >> 16);
        return (n + 1);
    }

    static void Main(string[] args)
    {
        Program p = new Program();
        foreach (int n in p.GenerateSequence(1000))
        {
            Console.WriteLine(n);
        }

        Console.ReadKey();
    }
}
2020-07-28