开发者

Count bits used in int

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;
}


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


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.


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))


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;
}


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)".


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;
}


Integer.toBinaryString(value).length()


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;


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;
}


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;

}


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜