4

If you have the binary number 10110 how can I get it to return 5? e.g a number that tells how many bits are used? There are some likewise examples listed below:

  • 101 should return 3
  • 000000011 should return 2
  • 11100 should return 5
  • 101010101 should return 9

How can this be obtained the easiest way in Java? I have come up with the following method but can i be done faster:

public static int getBitLength(int value)
{
    if (value == 0)
    {
        return 0;
    }
    int l = 1;
    if (value >>> 16 > 0) { value >>= 16; l += 16; }
    if (value >>> 8 > 0) { value >>= 8; l += 8; }
    if (value >>> 4 > 0) { value >>= 4; l += 4; }
    if (value >>> 2 > 0) { value >>= 2; l += 2; }
    if (value >>> 1 > 0) { value >>= 1; l += 1; }
    return l;
}
sigvardsen
  • 1,531
  • 3
  • 26
  • 44

11 Answers11

12

Easiest?

32 - Integer.numberOfLeadingZeros(value)

If you are looking for algorithms, the implementors of the Java API agree with your divide-and-conquer bitshifting approach:

public static int numberOfLeadingZeros(int i) {
    if (i == 0)
        return 32;
    int n = 1;
    if (i >>> 16 == 0) { n += 16; i <<= 16; }
    if (i >>> 24 == 0) { n +=  8; i <<=  8; }
    if (i >>> 28 == 0) { n +=  4; i <<=  4; }
    if (i >>> 30 == 0) { n +=  2; i <<=  2; }
    n -= i >>> 31;
    return n;
}

Edit: As a reminder to those who trust in the accuracy of floating point calculations, run the following test harness:

public static void main(String[] args) {
    for (int i = 0; i < 64; i++) {
        long x = 1L << i;
        check(x);
        check(x-1);
    }
}

static void check(long x) {
    int correct = 64 - Long.numberOfLeadingZeros(x);
    int floated = (int) (1 + Math.floor(Math.log(x) / Math.log(2)));
    if (floated != correct) {
        System.out.println(Long.toString(x, 16) + " " + correct + " " + floated);
    }
}

The first detected deviation is:

ffffffffffff 48 49
Graham Russell
  • 997
  • 13
  • 24
meriton
  • 68,356
  • 14
  • 108
  • 175
6

Unfortunately there is no Integer.bitLength() method that would give you the answer directly.

An analogous method exists for BigInteger, so you could use that one:

BigInteger.valueOf(value).bitLength()

Constructing the BigInteger object will make it somewhat less efficient, but that will only matter if you do it many millions of times.

starblue
  • 55,348
  • 14
  • 97
  • 151
2

You want to compute the base 2 logarithm of the number - specifically:

1 + floor(log2(value))

Java has a Math.log method which uses base e, so you can do:

1 + Math.floor(Math.log(value) / Math.log(2))
Chris
  • 10,337
  • 1
  • 38
  • 46
  • @meriton - Reasonably sure! The only problem is for a value of 0, when you end up with negative infinities and other nice things :) – Chris May 29 '10 at 16:58
  • Another certain problem are negative numbers, which have the highest bit set. – meriton May 29 '10 at 17:09
  • You are lucky, the rounding errors manifest only beyond the range of `int`. However, for `0xffffffffffffL`, your code would yield the incorrect result of 49, instead of 48. I'll add the test code to my answer. – meriton May 29 '10 at 17:17
1

Be careful what you ask for. One very fast technique is to do a table lookup:

int bittable [] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... };
int numbits (int v)
{
    return bittable [v];
}

where bittable contains an entry for every int. Of course that has complications for negative values. A more practical way would be to count the bits in bitfields of the number

int bittable [16] = {0, 1, 1, 2,  1, 2, 2, 3,  1, 2, 2, 3,  2, 3, 3, 4};
int numbits (int v)
{
    int s = 0;
    while (v != 0)
    {
         s += bittable [v & 15];
         v >>= 4;
    }
    return s;
}
wallyk
  • 56,922
  • 16
  • 83
  • 148
1

You really just want to find the position of the highest bit that is a 1. See this page, under the heading "Finding integer log base 2 of an integer (aka the position of the highest bit set)".

Victor Liu
  • 3,545
  • 2
  • 24
  • 37
1

From here, a way to do it with just bitwise-and and addition:

int GetHighestBitPosition(int value) {
  if (value == 0) return 0;

  int position = 1;
  if ((value & 0xFFFF0000) == 0) position += 16;
  if ((value & 0xFF00FF00) == 0) position += 8;
  if ((value & 0xF0F0F0F0) == 0) position += 4;
  if ((value & 0xCCCCCCCC) == 0) position += 2;
  if ((value & 0xAAAAAAAA) == 0) position += 1;

  return position;
}
Ken
  • 756
  • 4
  • 7
1

Integer.toBinaryString(value).length()

Jacob Abraham
  • 915
  • 9
  • 8
0

If you are looking for the fastest (and without a table, which is certainly faster), this is probably the one:

public static int bitLength(int i) {
    int len = 0;

    while (i != 0) {
        len += (i & 1);
        i >>>= 1;
    }

    return len;

}
cyanide
  • 3,885
  • 3
  • 25
  • 33
  • Why are you &'ing the len? @ 'len += (i & 1)'. Wouldn't this just give you a count on all the 1's in a bit string? – Y_Y Jun 03 '14 at 20:20
0

I think the rounded-up log_2 of that number will give you what you need.

Something like:

return (int)(Math.log(value) / Math.log(2)) + 1;
Oak
  • 26,231
  • 8
  • 93
  • 152
0
int CountBits(uint value)
{
    for (byte i = 32; i > 0; i--)
    {
        var b = (uint)1 << (i - 1);
        if ((value & b) == b)
            return i;
    }
    return 0;
}
realworldcoder
  • 699
  • 5
  • 16
0

Another solution is to use the length() of a BitSet which according to the API

Returns the "logical size" ... the index of the highest set bit ... plus one.

To use the BitSet you need to create an array. So it is not as simple as starting with a pure int. But you get it out of the JDK box - tested and supported. It would look like this:

  public static int bitsCount(int i) {
    return BitSet.valueOf(new long[] { i }).length();
  }

Applied to the examples in the question:

  bitsCount(0b101); // 3
  bitsCount(0b000000011); // 2
  bitsCount(0b11100); // 5
  bitsCount(0b101010101); // 9

When asking for bits the BitSetseems to me to be the appropriate data structure.

LuCio
  • 5,055
  • 2
  • 18
  • 34