1

Lets say x = 1110 (14 in Dec) and I want to find the 2nd set bit from the right, 0100 (4 in Dec)

Yet another example, lets say x = 10110010 (178 in Dec) and I want the 3rd set bit from the right,i.e, 00100000 (32 in Dec)

How to find it? Is there a hack?

Prasath Govind
  • 720
  • 2
  • 10
  • 30

3 Answers3

4

Subtracting one from a number will clear the least-significant bit which was set, while setting bits below that. ANDing with the original number will then leave a number which was equal to the original except with the original lowest set bit clear. This procedure may be iterated N times to yield a number with the lowest N set bits clear. The bit which is changed by the Nth iteration (if any) will be the Nth lowest bit that was set in the original.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • Did I capture your steps correctly? Let, the bit set we want from the right of x = n `while(n--) num = x & (x-1)` – Prasath Govind Nov 02 '15 at 17:35
  • Clearing the rightmost bit would be `x &= x-1;` [or, if preferred, `x=x & (x-1);`, but not using `num` in any case] , so clearing the rightmost n bits would be `while(n--) x &= x-1;`. If you want the value of the last bit cleared, however, you'll have to clear n-1 bits, then save x, then clear the next bit. The difference will be the value of the newly-cleared bit. – supercat Nov 02 '15 at 18:31
1

Assuming a two's complement signed 32-bit integer called number is the input (hence only counting bits 0 to 30 in the for loop):

int number = (1 << 3) | 1; // this is the input, it can be whatever you like
int currentLsbCount = 0;
int desiredLsbCount = 2; // this is your n
int foundLsb = 0;
int foundLsbIndex = 0;

for (int i = 0; i < 31; i++)
{
    int bit = (number >> i) & 1;

    if (bit == 1)
    {
        ++currentLsbCount;
    }

    if (currentLsbCount == desiredLsbCount)
    {
        foundLsb = number & (1 << i);

        foundLsbIndex = i;

        break;
    }
}

foundLsb will hold the value or will be zero if the input was zero; foundLsbIndex will hold the index of the bit.

As far as I know you would have to iterate. There is no quicker method than looping through the bits. You could add some skip logic in, but it would not improve the worst case timing. For instance:

if ((number & ((1 << x) - 1)) == number)
{
    // the bottom x bits are zero...
}

This would increase the number of operations for the worst case.

keith
  • 5,122
  • 3
  • 21
  • 50
1

In VB.NET, I'd possibly do the following:

Private Function ReturnBit(input As Long, num As Long) As Long
    Dim iResult As Long = 0    'Counts set bits.
    Dim work As Long = input   'Working copy of input.

    'Looping from the LSB to the MSB of a byte. Adjust for desired 
    'length, 15 for 2 bytes, 31 for 4 bytes, etc.
    For i As Integer = 0 To 7
        'If the working variable is 0, the input does not contain as
        'many set bits as required. Return -1 if you wish.
        If work = 0 Then Return 0

        'Add the now LSB if 1, 0 otherwise. 
        iResult += (work And 1)

        'iResult contains the number of set bits now. If this is
        'the requested number, return this number. If you're just after
        'the position, just return i instead. Instead of 2^i it could be
        'more efficient to use 1<<i, but I'd rely on the compiler for
        'this.
        If iResult = num Then Return CLng(2 ^ i)

        'Remove the LSB from the working copy.
        work >>= 1
    Next
    Return 0    'Not enough set bits in input.
End Function
  • @greybeard, i is a loop checking the LSB...MSB bits of a byte. For longer inputs, the count can be increased appropriately. 2 bytes constitute an UShort, 4 bytes an UInteger, 8 Bytes an ULong. the arguments could be shortened a bit, but I do not know, what the OP wants this function for. Added comments to the code. –  Jul 27 '17 at 11:00
  • What would happen if you used `Do … Loop` instead of the `For`-loop? – greybeard Jul 27 '17 at 20:36
  • @greybeard, that would work as well, of course, but don't forget to increase the `i` next to the loop's end. That's the nice things about `For...Next` loops: the iterator is increased automatically. I make use of this each time there is a known number of iterations. –  Jul 28 '17 at 01:49
  • (`don't forget to increase the` i `[in a Do … Loop]` - I tried to ask about a loop that does not count. The catch is that VBs `>>=` is "arithmetic": if the high bit was set, it wouldn't terminate. One alternative is to start "anding" with a 1 and shift that to the left until the value turns 0 (or greater than (a positive) `input`. ("Fast" and somewhat of [`a hack`](http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan) is handling set bits from lowest to highest as in [supercat's answer](https://stackoverflow.com/a/33481789/3789665).)) – greybeard Jul 28 '17 at 05:51
  • The linked "hack" became an Intel machine instruction now known as [BLSI](https://en.wikipedia.org/wiki/Bit_Manipulation_Instruction_Sets#BMI1_.28Bit_Manipulation_Instruction_Set_1.29). Supercat's answer surely works, but it requires a loop as well. My shift operation has nothing to do with loop control, the control variable is the `i` which takes values from 0...7, then terminates in any case. `work >> 1` does just prepare the working copy for the next iteration by exposing a new LSB. The number of significant bits is pretty much freely choosable, just adjust `i` and possibly the data types. –  Jul 28 '17 at 06:03