Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing bit at specific index

I'm basically trying to remove a bit from an integer at a specific index. That is, I do not want to unset/clear the bit; I actually want to strip it, so that every higher bit moves down, replacing the respective bit at its position. Visually, this could be compared to deleting an element from an array or removing a character from a string.

For the sake of clarity, some examples:

1011011 (original number)
    ^ index = 2
0101111 (result)

10000000000000000000000000000001
^ index = 31
00000000000000000000000000000001

1111111111111111111111111111110
                              ^ index = 0
0111111111111111111111111111111

Full of confidence, I started shifting some bits, and came up with the following Java method...

public static int removeBit(int num, int i) {
    int out = (num >>> (i + 1)) << i;
    out  |= (num << (32 - i)) >>> (32 - i);
    return out;
}

... which almost always works, except for some extreme cases:

10000000000000000000000000000001 (= Integer.MAX_VALUE - 1)
^ index = 31, results in:
10000000000000000000000000000001

1011011
      ^ index = 0, results in:
1111111

In other words, if the index is 0 or 31 (least or most significant bit), my method will output garbage.

I can't seem to wrap my head around it, and that's why I'm asking: How can I remove an arbitrary bit in a 32-bit integer?

I'm especially looking for the most performant way to do it in Java (smallest possible memory and CPU consumption), since this operation has to run at least a couple million times. That's why something like "convert it into a string, remove the char and convert it back" is out of the question.

like image 221
MCL Avatar asked Jan 21 '14 12:01

MCL


1 Answers

As explained in the comments, the shift counts rolled over to >= 32, which caused trouble.

Anyway, let's derive a way to do it.

Start by considering the two "pieces", the low piece (which gets copied in its original position and may be anywhere between 0 .. 31 bits long) and the high piece (which gets shifted down by one, and can also be between 0 .. 31 bits long). The total length of the pieces is always 31.

The mask for the low piece is obvious: ~(-1 << i)

Which makes the mask for the high piece obvious: ~lowmask << 1. The high piece is shifted anyway, so that shift can go.

Now all that's left is to take the pieces and OR them together, and you would get

static int removeBit(int x, int i)
{
    int mask = ~(-1 << i);
    return (x & mask) | ((x >>> 1) & ~mask);
}

Throw out the double negation:

static int removeBit(int x, int i)
{
    int mask = -1 << i;
    return (x & ~mask) | ((x >>> 1) & mask);
}
like image 182
harold Avatar answered Sep 17 '22 12:09

harold