generate all n bit binary numbers in a fastest way

2019-04-11 02:18发布

问题:

How do I generate all possible combinations of n-bit strings? I need to generate all combinations of 20-bit strings in a fastest way possible. (my current implementation is done with bitwise AND and right shift operation, but I am looking for a faster technique).

I need to store the bit-strings in an array (or list) for the corresponding decimal numbers, like --

0 --> 0 0 0

1 --> 0 0 1

2 --> 0 1 0 ... etc.

any idea?

回答1:

for (unsigned long i = 0; i < (1<<20); ++i) {
    // do something with it
}

An unsigned long is a sequence of bits.

If what you want is a string of characters '0' and '1', then you could convert i to that format each time. You might be able to get a speed-up taking advantage of the fact that consecutive numbers normally share a long initial substring. So you could do something like this:

char bitstring[21];
for (unsigned int i = 0; i < (1<<10); ++i) {
    write_bitstring10(i, bitstring);
    for (unsigned int j = 0; j < (1<<10); ++j) {
        write_bitstring10(j, bitstring + 10);
        // do something with bitstring
    }
}

I've only increased from 1 loop to 2 there, but I do a little over 50% as much converting from bits to chars as before. You could experiment with the following:

  • use even more loops
  • split the loops unevenly, maybe 15-5 instead of 10-10
  • write a function that takes a string of zeros and ones, and adds 1 to it. It's pretty easy: find the last '0', change it to a '1', and change all the '1's after it to '0'.

To fiendishly optimize write_bitstring, multiples of 4 are good because on most architectures you can blit 4 characters at a time in a word write:

To start:

assert(CHAR_BIT == 8);
uint32_t bitstring[21 / 4]; // not char array, we need to ensure alignment
((char*)bitstring)[20] = 0; // nul terminate

Function definition:

const uint32_t little_endian_lookup = {
    ('0' << 24) | ('0' << 16) | ('0' << 8) | ('0' << 0),
    ('1' << 24) | ('0' << 16) | ('0' << 8) | ('0' << 0),
    ('1' << 24) | ('1' << 16) | ('0' << 8) | ('0' << 0),
    // etc.
};
// might need big-endian version too

#define lookup little_endian_lookup // example of configuration

void write_bitstring20(unsigned long value, uint32_t *dst) {
    dst[0] = lookup[(value & 0xF0000) >> 16];
    dst[1] = lookup[(value & 0x0F000) >> 12];
    dst[2] = lookup[(value & 0x00F00) >> 8];
    dst[3] = lookup[(value & 0x000F0) >> 4];
    dst[4] = lookup[(value & 0x0000F)];
}

I haven't tested any of this: obviously you're responsible for writing a benchmark that you can use to experiment.



回答2:

Python

>> n = 3
>> l = [bin(x)[2:].rjust(n, '0') for x in range(2**n)]
>> print l
['000', '001', '010', '011', '100', '101', '110', '111']


回答3:

Just output numbers from 0 to 2^n - 1 in binary representation with exactly n digits.



回答4:

for (i = 0; i < 1048576; i++) {
   printf('%d', i);
}

conversion of the int version i to binary string left as an exercise to the OP.



回答5:

This solution is in Python. (versions 2.7 and 3.x should work)

>>> from pprint import pprint as pp
>>> def int2bits(n):
    return [(i, '{i:0>{n}b}'.format(i=i, n=n)) for i in range(2**n)]

>>> pp(int2bits(n=4))
[(0, '0000'),
 (1, '0001'),
 (2, '0010'),
 (3, '0011'),
 (4, '0100'),
 (5, '0101'),
 (6, '0110'),
 (7, '0111'),
 (8, '1000'),
 (9, '1001'),
 (10, '1010'),
 (11, '1011'),
 (12, '1100'),
 (13, '1101'),
 (14, '1110'),
 (15, '1111')]
>>> 

It finds the width of the maximum number and then pairs the int with the int formatted in binary with every formatted string being right padded with zero's to fill the maximum width if necessary. (The pprint stuff is just to get a neat printout for this forum and could be left out).



回答6:

you can do it by generate all integer number in binary representation from 0 to 2^n-1

static int[] res;
    static int n;
    static void Main(string[] args)
    {
        n = Convert.ToInt32(Console.ReadLine());
        res = new int [n];
        Generate(0);

    }

    static void Generate(int start)
    {
        if (start > n)
            return;
        if(start == n)
        {
            for(int i=0; i < start; i++)
            {
                Console.Write(res[i] + " ");
            }
            Console.WriteLine();
        }

        for(int i=0; i< 2; i++)
        {
            res[start] = i;
            Generate(start + 1);
        }
    }