1

Is there a quick and easy way to unset all the bits in a number except the most significant bit? In other words I would like to take an integer x and apply & operator to it where the operand is 1 left-shifted by total number of bits in x. Example:

return UnsetAllBitsExceptMSB(400);

should return 256

rpetrk
  • 25
  • 7
  • 1
    The quick and easy way is to do exactly what you said: `I would like to take an integer x and apply & operator to it where the operand is 1 left-shifted by total number of bits in x` – Neil Locketz Jun 15 '17 at 17:39
  • if the number is < 256 do you want it to unset everything but the MSB, which would return zero? You could use a bit mask if this is the case. – Billy Ferguson Jun 15 '17 at 17:41
  • Right, what I am looking for is a quick way to determine the total number of bits in x. – rpetrk Jun 15 '17 at 17:42
  • No, suppose the number is 7 (111 in binary) the return would be 4 (100). – rpetrk Jun 15 '17 at 17:43
  • You mean 128 = A & 0x80 – jdweng Jun 15 '17 at 17:44
  • What range of input values do you need to support? – Lasse V. Karlsen Jun 15 '17 at 17:58
  • Up to 2147483648. Only positive values. – rpetrk Jun 15 '17 at 18:00
  • What's the overall goal and the performance targets here? The most straightforward to read is to log, round down, and exponentiate. If you need "maximum performance" on this, what are the constraints? – Damien_The_Unbeliever Jun 15 '17 at 18:10
  • @Damien_The_Unbeliever the overall goal was to avoid looping if possible. I also have a version of the function you describe but haven't compared its performance to the loop version. – rpetrk Jun 15 '17 at 18:35
  • 1
    Obligatory link for future reference: [bit twiddling hacks](http://graphics.stanford.edu/%7Eseander/bithacks.html). This is a variation on "round up to the next highest power of 2" (you want the power just before that). – Jeroen Mostert Jun 15 '17 at 19:23

4 Answers4

5

Yes, there is a trick:

private int UnsetAllBitsExceptMSB(int x)
{
  x |= x >> 16;
  x |= x >> 8;
  x |= x >> 4;
  x |= x >> 2;
  x |= x >> 1;
  x ^= x >> 1;
  return x;
}

This works by first turning on all the bits to the right of the most significant set bit (00110000 becomes 001111111). It then uses XOR with the result right shifted one to turn all but the first bit off. (00111111 XOR with 00011111 = 00100000)

There are other ways of doing this that will perform better in some circumstances, but this has a predictable performance no matter the input. (5 OR, 6 right shifts, and an XOR).

Robert McKee
  • 21,305
  • 1
  • 43
  • 57
1

I'm not sure about "quick and easy", but you don't need any bitwise operations for this... your question could be reworded as "how can I find the largest power of 2 that's smaller than my input? So a simple way to do that:

private int UnsetAllBitsExceptMSB(int x)
{
    int y = 1;
    while (y <= x)
    {
        y*=2;
    }
    return y / 2;
}
GendoIkari
  • 11,734
  • 6
  • 62
  • 104
0

Given int represents a 32-bit signed integer I guess the first bit shouldn't be taken into consideration. So, this should get what you want:

int result = 1 << 30;
while ((result & myInt) != result)
    result >>= 1;
dcg
  • 4,187
  • 1
  • 18
  • 32
  • Yep, that works. I was hoping there might be a non-loop trick. Thanks. – rpetrk Jun 15 '17 at 18:19
  • @rpetrk I think there might not be one 'cause you can't predict where one bit is going to be set, that's why I start from higher positive power of two (of a 32-bit signed integer) and go down until I find the power I want. – dcg Jun 15 '17 at 18:26
  • that makes sense. Your code is straightforward and does the job. I can't upvote yet but I tried. – rpetrk Jun 15 '17 at 18:33
0

Hi here is another option to consider:

public static int GetTopBitValue(int number)
{
    if (number < 0)
    {
        throw new ArgumentOutOfRangeException("Non negative numbers are expected");
    }

    int i = 1;
    while (i <= number)
        i = i << 1;

    return i >> 1;
}

Edited to cover corner cases.

Artak
  • 2,819
  • 20
  • 31
  • 1
    I think it's the equivalent to the answer of @GendoIkari but using bitwise operations. Except that when number is 1 your code never finishes. – dcg Jun 15 '17 at 18:25
  • Thanks dct. I've updated it to cover the corner cases – Artak Jun 15 '17 at 18:41