I need to generate a random number, but it needs to be selected from the set of binary numbers with equal numbers of set bits. E.g. choose a random byte value with exactly 2 bits set...
00000000 - no
00000001 - no
00000010 - no
00000011 - YES
00000100 - no
00000101 - YES
00000110 - YES
...
=> Set of possible numbers 3, 5, 6...
Note that this is a simplified set of numbers. Think more along the lines of 'Choose a random 64-bit number with exactly 40 bits set'. Each number from the set must be equally likely to arise.
If you don't have the convenience of Python's
random.sample
, you might do this in C using the classic sequential sampling algorithm:The cost of the above will be dominated by the cost of generating the random numbers (true in the other solutions, also). You can optimize this a bit if you have a good prng by batching: for example, since you know that the random numbers will be in steadily decreasing ranges, you could get the random numbers for
n
throughn-3
by getting a random number in the range0..(n * (n - 1) * (n - 2) * (n - 3))
and then extracting the individual random numbers:The maximum value of
n
is presumably64
or 26, so the maximum value of the product above is certainly less than 224. Indeed, if you used a 64-bit prng, you could extract as many as 10 random numbers out of it. However, don't do this unless you know the prng you use produces independently random bits.Here is another option which is very simple and reasonably fast in practice.
Repeat until count equals the number of bits you want set.
This will only be slow when the number of bits you want set (call it
k
) is more than half the word length (call itN
). In that case, use the algorithm to setN
-k
bits instead and then flip all the bits in the result.I bet the expected running time here is pretty good, although I am too lazy/stupid to compute it precisely right now. But I can bound it as less than 2*
k
... The expected number of flips of a coin to get "heads" is two, and each iteration here has a better than 1/2 chance of succeeding.I have found an elegant solution: random-dichotomy.
Idea is that on average:
C code to compile with gcc (to have __builtin_popcountll):
In general less than 10 loops are needed to reach the requested number of bits (and with luck it can take 2 or 3 loops). Corner cases (nb_bits=0,1,width-1,width) are working even if a special case would be faster.
Example of result:
Of course, you need a good prng. Otherwise you can face an infinite loop.
I have another suggestion based on enumeration: choose a random number i between 1 and n choose k, and generate the i-th combination. For example, for n = 6, k = 3 the 20 combinations are:
Let's say we randomly choose combination number 7. We first check whether it has a 1 in the last position: it has, because the first 10 (5 choose 2) combinations have. We then recursively check the remaining positions. Here is some C++ code:
To be fast, we use precalculated binomial coefficients in
binCoeff
. The functionrandomRange
returns a random integer between the two bounds (inclusively).I did some timings (source). With the C++11 default random number generator, most time is spent in generating random numbers. Then this solution is fastest, since it uses the absolute minimum number of random bits possible. If I use a fast random number generator, then the solution by mic006 is fastest. If
k
is known to be very small, it's best to just randomly set bits untilk
are set.Do a random selection from the set of all bit positions, then set those bits.
Example in Python:
Results of running the above 10 times:
Say the number of bits to set is b and the word size is w. I would create a vector v of of length w with the first b values set to 1 and the rest set to 0. Then just shuffle v.