Efficient random permutation of n-set-bits

后端 未结 5 783
天命终不由人
天命终不由人 2021-01-21 13:52

For the problem of producing a bit-pattern with exactly n set bits, I know of two practical methods, but they both have limitations I\'m not happy with.

Fir

5条回答
  •  无人共我
    2021-01-21 14:29

    Seems like you want a variant of Floyd's algorithm:

    Algorithm to select a single, random combination of values?

    Should be especially useful in your case, because the containment test is a simple bitmask operation. This will require only k calls to the RNG. In the code below, I assume you have randint(limit) which produces a uniform random from 0 to limit-1, and that you want k bits set in a 32-bit int:

    mask = 0;
    for (j = 32 - k; j < 32; ++j) {
        r = randint(j+1);
        b = 1 << r;
        if (mask & b) mask |= (1 << j);
        else mask |= b;
    }
    

    How many bits of entropy you need here depends on how randint() is implemented. If k > 16, set it to 32 - k and negate the result.

    Your alternative suggestion of generating a single random number representing one combination among the set (mathematicians would call this a rank of the combination) is simpler if you use colex order rather than lexicographic rank. This code, for example:

    for (i = k; i >= 1; --i) {
        while ((b = binomial(n, i)) > r) --n;
        buf[i-1] = n;
        r -= b;
    }
    

    will fill the array buf[] with indices from 0 to n-1 for the k-combination at colex rank r. In your case, you'd replace buf[i-1] = n with mask |= (1 << n). The binomial() function is binomial coefficient, which I do with a lookup table (see this). That would make the most efficient use of entropy, but I still think Floyd's algorithm would be a better compromise.

提交回复
热议问题