Search code examples
c++permutationcombinatoricshamming-distance

computing permutation of specific bits in a number


As part of my master thesis, I get a number (e.g. 5 bits) with 2 significant bits (2nd and 4th). This means for example x1x0x, where $x \in {0,1}$ (x could be 0 or 1) and 1,0 are bits with fixed values.

My first task is to compute all the combinations of the above given number , 2^3 = 8. This is called S_1 group.

Then I need to compute 'S_2' group and this is all the combinations of the two numbers x0x0x and x1x1x(this means one mismatch in the significant bits), this should give us $\bin{2}{1} * 2^3 = 2 * 2^3 = 16.

EDIT Each number, x1x1x and x0x0x, is different from the Original number, x1x0x, at one significant bit.

Last group, S_3, is of course two mismatches from the significant bits, this means, all the numbers which pass the form x0x1x, 8 possibilities.

The computation could be computed recursively or independently, that is not a problem.

I would be happy if someone could give a starting point for these computations, since what I have is not so efficient.

EDIT Maybe I chose my words wrongly, using significant bits. What I meant to say is that a specific places in a five bits number the bit are fixed. Those places I defined as specific bits.

EDIT I saw already 2 answers and it seems I should have been clearer. What I am more interested in, is finding the numbers x0x0x, x1x1x and x0x1x with respect that this is a simply example. In reality, the group S_1 (in this example x1x0x) would be built with at least 12 bit long numbers and could contain 11 significant bits. Then I would have 12 groups...

If something is still not clear please ask ;)


Solution

  • #include <vector>
    #include <iostream>
    #include <iomanip>
    
    using namespace std;
    
    int main()
    {
        string format = "x1x0x";
    
        unsigned int sigBits = 0;
        unsigned int sigMask = 0;
        unsigned int numSigBits = 0;
        for (unsigned int i = 0; i < format.length(); ++i)
        {
            sigBits <<= 1;
            sigMask <<= 1;
            if (format[i] != 'x')
            {
                sigBits |= (format[i] - '0');
                sigMask |= 1;
                ++numSigBits;
            }
        }
    
        unsigned int numBits = format.length();
        unsigned int maxNum = (1 << numBits);
    
        vector<vector<unsigned int> > S;
        for (unsigned int i = 0; i <= numSigBits; i++)
            S.push_back(vector<unsigned int>());
    
        for (unsigned int i = 0; i < maxNum; ++i)
        {
            unsigned int changedBits = (i & sigMask) ^ sigBits;
    
            unsigned int distance = 0;
            for (unsigned int j = 0; j < numBits; j++)
            {
                if (changedBits & 0x01)
                    ++distance;
                changedBits >>= 1;
            }
    
            S[distance].push_back(i);
        }
    
        for (unsigned int i = 0; i <= numSigBits; ++i)
        {
            cout << dec << "Set with distance " << i << endl;
            vector<unsigned int>::iterator iter = S[i].begin();
            while (iter != S[i].end())
            {
                cout << hex << showbase << *iter << endl;
                ++iter;
            }
    
            cout << endl;
        }
    
        return 0;
    }
    

    sigMask has a 1 where all your specific bits are. sigBits has a 1 wherever your specific bits are 1. changedBits has a 1 wherever the current value of i is different from sigBits. distance counts the number of bits that have changed. This is about as efficient as you can get without precomputing a lookup table for the distance calculation.