Igor Tupitsyn
Igor Tupitsyn

Reputation: 1193

Java: Extracting integers from a BitSet, each of which consists of specific bit number

If I have a Java BitSet with a length of 500 bits and, I know, it contains 100 integers, each of which is represented by 5 bits, how do I extract an array of these integers? Using some of the examples online, I came up with the following:

static int[] bitSet2Ints(BitSet bs, int bitNumber) 
    {
        int[] temp = new int[bs.length() / bitNumber];

        for (int i = 0; i < temp.length; i++)
        {
            for (int j = 0; j < bitNumber; j++)
            {
                if (bs.get(i * bitNumber + j))
                {
                    temp[i] |= 1 << j;
                }
            }
        }

        return temp;
    }

I was wondering if this is the correct way to do it.

Thank you!

EDIT: Apparently, the code does not produce the expected result. I did a unit test and the input and output were completely different:

This is my input:

Binary String: 0 is 00000
Binary String: 1 is 00001
Binary String: 2 is 00010
Binary String: 3 is 00011
Binary String: 4 is 00100
Binary String: 5 is 00101
Binary String: 6 is 00110
Binary String: 7 is 00111
Binary String: 8 is 01000
Binary String: 9 is 01001
Binary String: 10 is 01010
Binary String: 11 is 01011
Binary String: 12 is 01100
Binary String: 13 is 01101
Binary String: 14 is 01110
Binary String: 15 is 01111
Binary String: 16 is 10000
Binary String: 17 is 10001
Binary String: 18 is 10010
Binary String: 19 is 10011
Binary String: 20 is 10100
Binary String: 21 is 10101
Binary String: 22 is 10110
Binary String: 23 is 10111
Binary String: 24 is 11000
Binary String: 25 is 11001
Binary String: 26 is 11010
Binary String: 27 is 11011
Binary String: 28 is 11100
Binary String: 29 is 11101
Binary String: 30 is 11110
Binary String: 31 is 11111

This is my output:

NUMBER OF VALUES EXTRACTED: 32
INTEGER CONVERTED: 0
INTEGER CONVERTED: 16
INTEGER CONVERTED: 8
INTEGER CONVERTED: 24
INTEGER CONVERTED: 4
INTEGER CONVERTED: 20
INTEGER CONVERTED: 12
INTEGER CONVERTED: 28
INTEGER CONVERTED: 2
INTEGER CONVERTED: 18
INTEGER CONVERTED: 10
INTEGER CONVERTED: 26
INTEGER CONVERTED: 6
INTEGER CONVERTED: 22
INTEGER CONVERTED: 14
INTEGER CONVERTED: 30
INTEGER CONVERTED: 1
INTEGER CONVERTED: 17
INTEGER CONVERTED: 9
INTEGER CONVERTED: 25
INTEGER CONVERTED: 5
INTEGER CONVERTED: 21
INTEGER CONVERTED: 13
INTEGER CONVERTED: 29
INTEGER CONVERTED: 3
INTEGER CONVERTED: 19
INTEGER CONVERTED: 11
INTEGER CONVERTED: 27
INTEGER CONVERTED: 7
INTEGER CONVERTED: 23
INTEGER CONVERTED: 15
INTEGER CONVERTED: 31

Upvotes: 0

Views: 441

Answers (2)

TheConstructor
TheConstructor

Reputation: 4465

I guess @Malt already gave the solution with the best readability. I hope this is the fastest solution as get(int, int) creates another BitSet and checking each bit on its own has too many CPU-paths.

I will copy the internal representation of the BitSet to a new long-array and then resort to binary integer arithmethics to get consecutive sections of bitNumber bits.

static int[] bitSet2Ints(BitSet bs, int bitNumber) {
    if (bitNumber < 1 || bitNumber > Integer.SIZE) {
        throw new IllegalArgumentException("bitNumber needs to be between 1 and " + Integer.SIZE);
    }

    int mask = 0;
    for (int i = 0; i < bitNumber; i++) {
        mask = mask << 1 | 1;
    }

    long[] longArray = bs.toLongArray();
    int[] result = new int[bs.length() / bitNumber];
    for (int i = 0; i < result.length; i++) {
        final int globalStartBit = i * bitNumber;
        final int localStartBit = globalStartBit % Long.SIZE;
        result[i] = (int) (longArray[globalStartBit / Long.SIZE] >>> localStartBit) & mask;
        if (Long.SIZE - localStartBit < bitNumber) {
            result[i] |= (int) (longArray[globalStartBit / Long.SIZE + 1] << Long.SIZE - localStartBit) & mask;
        }
    }

    return result;
}

As >>> cycles bits around you could use globalStartBit with it and as << cycles, too, you could use just - localStartBit as its right argument.

Upvotes: 1

Malt
Malt

Reputation: 30285

What type of "correct" are we talking here?

Your code looks fine, and seems to be a perfectly reasonable solution to your problem. If it were up to me, I would have written something a little less nested, to make it easier to read. Maybe something like this:

static byte[] bitSet2Ints(BitSet bs, int bitNumber) {
    byte[] temp = new byte[bs.length() / bitNumber];

    for (int i = 0; i < temp.length; i++){
        temp[i] = bs.get(i * bitNumber, (i + 1) * bitNumber).toByteArray()[0];
    }

    return temp;
}

*haven't tested this code

You could also add parameter checks to avoid invalid input:

    if (bs == null){
        throw new NullPointerException("The bit set cannot be null!");
    }
    if (bitNumber <1 || bitNumber > 7){
        throw new IllegalArgumentException("Illegal bit count");
    }

Upvotes: 1

Related Questions