34

This is probably pretty basic, but to save me an hour or so of grief can anyone tell me how you can work out the number of bits required to represent a given positive integer in Java?

e.g. I get a decimal 11, (1011). I need to get the answer, 4.

I figured if I could work out how to set all the bits other than the most significant bit to 0, and then >>> it, I'd get my answer. But... I can't.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
joinJpegs
  • 1,287
  • 3
  • 14
  • 21

14 Answers14

35

Well, the answer is pretty simple. If you have an int value:

int log2(int value) {
    return Integer.SIZE - Integer.numberOfLeadingZeros(value);
}

The same exists for Long...

[Edit] If shaving milliseconds is an issue here, Integer.numberOfLeadingZeros(int) is reasonably efficient, but still does 15 operations... Expanding a reasonable amount of memory (300 bytes, static) you could shave that to between 1 and 8 operations, depending on the range of your integers.

Jin Kwon
  • 20,295
  • 14
  • 115
  • 184
Varkhan
  • 16,601
  • 5
  • 31
  • 24
  • 7
    This is the fastest solution. And far easier to follow than the accepted answer! – TofuBeer Apr 17 '11 at 16:49
  • 2
    This may be the fastest solution but technically speaking it is not foolproof. Try calling it with value = 0, the result is: 0. This is wrong for 2 reasons: first of all, mathematically speaking log2(0) is undefined. Second, in the context of the original question: when you want to store an integer whose value is zero you will need at least one bit to do so. – Matthias Nov 30 '12 at 22:58
  • If that is the only issue it can be special cased, and still be easier to understand and more performant than the other answers. – TofuBeer Mar 20 '13 at 14:16
  • 2
    Out of the javadoc: Note that this method is closely related to the logarithm base 2. For all positive int values x: `floor(log2(x)) = 31 - numberOfLeadingZeros(x)` `ceil(log2(x)) = 32 - numberOfLeadingZeros(x - 1)` – mike Aug 20 '13 at 16:42
31

Well, you can just count how many times you shift right before you're left with just zero:

int value = 11;
int count = 0;
while (value > 0) {
    count++;
    value = value >> 1;
}
Thiago Negri
  • 5,221
  • 2
  • 28
  • 39
i_am_jorf
  • 53,608
  • 15
  • 131
  • 222
  • 1
    d'oh! yes that's pretty simple. I was expecting some great bit-twiddling wizardry... Thanks for the quick reply, I'll use that for now, but I'd be interested to see if there are any methods without loops and the such. – joinJpegs Mar 25 '09 at 02:33
  • Well, you could unroll the loop since it should be bounded at 32 iterations (or 64--however Java works). – i_am_jorf Mar 25 '09 at 02:38
  • int is 32 bits in Java, long is 64. – TofuBeer Mar 25 '09 at 02:59
  • OK, I posted you a method with no loop. It still requires a few steps though ;). – AHelps Mar 25 '09 at 05:45
  • 2
    Not so good for negatives. Try `while (value != 0) { ++count; value >>>= 1; }`. >>> is the logical (no sign-extension) right shift operator. – Tom Hawtin - tackline Mar 25 '09 at 11:18
  • @whataheck `>> 1` divides by 2 rounding down to minus infinity (so -1 "divided by 2" is still -1). `>>> 1` treats the number as if it was positive (unsigned) and divides by 2. – Tom Hawtin - tackline Jun 07 '11 at 11:34
  • @Tom Hawtin - tackline ok .. but when I try to use value >> 1; in my program,thers a compliation error "value >> 1 " is not a statement. – crackerplace Jun 08 '11 at 13:09
  • @Tom Hawtin - tackline Also >> 1 is for negative numbers ,but in java we dont have unsigned numbers so every number though its a negative one is represented in bits before this operation takes place ,,.. then why do we have 2 operators one for positive and other for negative numbers .. – crackerplace Jun 08 '11 at 13:11
  • @whataheck `value >> 1` is an expression, not a statement. So you'd need to do something like `value = value >> 1;` or `value >>= 1;` (where a statement is valid). `>>` and `>>>` work on both positive numbers, and produce the same results. The difference is how they treat negative numbers. Assembly languages typically have two mnemonics, such as `ASR` and `LSR` for arithmetic and logical shift right. – Tom Hawtin - tackline Jun 08 '11 at 13:19
27

My Java is a bit rusty, but the language-agnostic answer (if there is a "log2" function and a "floor" function available) would be:

numberOfBits = floor(log2(decimalNumber))+1

Assuming that "decimalNumber" is greater than 0. If it is 0, you just need 1 bit.

gnovice
  • 125,304
  • 15
  • 256
  • 359
  • 2
    I think decimalNumber should be decimalNumber + 1. log_2 256 is 8, whereas it needs 9 bits to represent. log_2 0 is undefined, but it needs zero bits to represent. – strager Mar 25 '09 at 02:47
  • 1
    @strager: I think you were close. I needed to use "floor" instead of "ceil", then add a +1. Obviously, a check is needed for "decimalNumber == 0" first. For example, try out 255 (which should give 8). – gnovice Mar 25 '09 at 03:00
  • @gnovice, Ah, good. I wasn't sure myself. Thanks for looking into it. =] – strager Mar 25 '09 at 03:03
  • It doesn't work for negative integers ofcourse, and sometimes you have to count bitcount for those aswell :) However, if you're compacting data, then I think a better approach would be to store a bit denoting sign, then storing the absolute value of that, since -1 would take up 32 bits where 1 would take up 2 (1 for the 1, and one for the sign). – Statement Aug 19 '09 at 16:26
  • @Statement: What you say makes sense, but the OP said they were only looking to get bit counts for positive integers. – gnovice Aug 19 '09 at 16:54
15

Integer.toBinaryString(number).length();

Good grief... why the down votes?

public class Main
{
    public static void main(final String[] argv)
    {
        System.out.println(Integer.toBinaryString(0).length());
        System.out.println(Integer.toBinaryString(1).length());
        System.out.println(Integer.toBinaryString(2).length());
        System.out.println(Integer.toBinaryString(3).length());
        System.out.println(Integer.toBinaryString(4).length());
        System.out.println(Integer.toBinaryString(5).length());
        System.out.println(Integer.toBinaryString(6).length());
        System.out.println(Integer.toBinaryString(7).length());
        System.out.println(Integer.toBinaryString(8).length());
        System.out.println(Integer.toBinaryString(9).length());
    }
}

Output:

1
1
2
2
3
3
3
3
4
4

Here is a simple test for the speed of the various solutions:

public class Tester 
{
    public static void main(final String[] argv) 
    {
        final int size;
        final long totalA;
        final long totalB;
        final long totalC;
        final long totalD;

        size = 100000000;

        totalA = test(new A(), size);
        totalB = test(new B(), size);
        totalC = test(new C(), size);
        totalD = test(new D(), size);

        System.out.println();
        System.out.println("Total D = " + totalD + " ms");
        System.out.println("Total B = " + totalB + " ms");
        System.out.println("Total C = " + totalC + " ms");
        System.out.println("Total A = " + totalA + " ms");

        System.out.println();
        System.out.println("Total B = " + (totalB / totalD) + " times slower");
        System.out.println("Total C = " + (totalC / totalD) + " times slower");
        System.out.println("Total A = " + (totalA / totalD) + " times slower");
    }

    private static long test(final Testable tester, 
                             final int      size)
    {
        final long start;
        final long end;
        final long total;

        start = System.nanoTime();
        tester.test(size);
        end   = System.nanoTime();
        total = end - start;

        return (total / 1000000);
    }

    private static interface Testable
    {
        void test(int size);
    }

    private static class A
        implements Testable
    {
        @Override
        public void test(final int size)
        {
            int value;

            value = 0;

            for(int i = 1; i < size; i++)
            {
                value += Integer.toBinaryString(i).length();
            }

            System.out.println("value = " + value);
        }    
    }

    private static class B
        implements Testable
    {
        @Override
        public void test(final int size)
        {
            int total;

            total = 0;

            for(int i = 1; i < size; i++)
            {
                int value = i;
                int count = 0;

                while (value > 0) 
                {
                    count++;
                    value >>= 1;
                }

                total += count;
            }

            System.out.println("total = " + total);
        }    
    }

    private static class C
        implements Testable
    {
        @Override
        public void test(final int size)
        {
            int total;
            final double log2;

            total = 0;
            log2  = Math.log(2);

            for(int i = 1; i < size; i++)
            {
                final double logX;
                final double temp;

                logX   = Math.log(i);
                temp   = logX / log2;                
                total += (int)Math.floor(temp) + 1;
            }

            System.out.println("total = " + total);
        }    
    }

    private static class D
        implements Testable
    {
        @Override
        public void test(final int size)
        {
            int total;

            total = 0;

            for(int i = 1; i < size; i++)
            {
                total += 32-Integer.numberOfLeadingZeros(i);
            }

            System.out.println("total = " + total);
        }    
    }
}

Output on my machine is:

value = -1729185023
total = -1729185023
total = -1729185023
total = -1729185023

Total D = 118 ms
Total B = 1722 ms
Total C = 4462 ms
Total A = 5704 ms

Total B = 14 times slower
Total C = 37 times slower
Total A = 48 times slower

For those of you complaining about speed... https://en.wikipedia.org/wiki/Program_optimization#Quotes.

Write the program to be readable first, then find out where it is slow, then make it faster. Before and after you optimize test the change. If the change wasn't large enough for the expense of making the code less readable don't bother with the change.

Krenair
  • 570
  • 5
  • 21
TofuBeer
  • 60,850
  • 18
  • 118
  • 163
  • You probably got the down votes because your solution is incredible expensive. – Daniel Brückner Mar 25 '09 at 04:36
  • 4
    didn't ask for it to be quick :-) – TofuBeer Mar 25 '09 at 04:45
  • It would seem that doing it 100,000,000 (on my desktop) probably would not be a bottleneck in a "real" program. – TofuBeer Apr 17 '11 at 18:54
  • 1
    Very nice benchmark! For the sake of completeness, you could add `BigInteger.valueOf(i).bitLength()` (which is on the slow side: on my machine, about 5 or 6 times slower than your **D**) – Unai Vivi Aug 31 '12 at 14:17
  • However, `BigInteger.bitLength()` is **bugged and unreliable** (at least in Java 6). http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=c134915207cae78f258c98a958f3?bug_id=6910473 – Unai Vivi Aug 31 '12 at 14:31
11

Taking the two based log of the number will report the number of bits required to store it.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
ojblass
  • 21,146
  • 22
  • 83
  • 132
  • A) -2 rep won't kill you B) this probably was in an audit and was a little ambiguous for the subject of the audit and was downvoted so it wouldn't ding someone again. – Foosh Feb 02 '15 at 20:53
  • 1
    so I guess it's `int(log2(n)) + 1` – pronebird Nov 19 '16 at 21:38
5

If you're trying to avoid a loop and you care about speed, you can use a method like this:

int value = ...;
int count = 0;
if( value < 0 ) { value = 0; count = 32; }
if( value >= 0x7FFF ) { value >>= 16; count += 16; }
if( value >= 0x7F ) { value >>= 8; count += 8; }
if( value >= 0x7 ) { value >>= 4; count += 4; }
if( value >= 0x3 ) { value >>= 2; count += 2; }
if( value >= 0x1 ) { value >>= 1; count += 1; }

Java doesn't have unsigned integers, so that first if( value < 0 ) is a little questionable. Negative numbers always set the most significant bit, so arguably require the full word to to represent them. Adapt that behavior if you care.

Incidentally, to handle a 64-bit integer, replace the if( value < 0 ) line with these two:

if( value < 0 ) { value = 0; count = 64; }
if( value >= 0x7FFFFFFF ) { value >>= 32; count += 32; }
AHelps
  • 1,782
  • 11
  • 17
  • this gives wrong results. for value = 4, this returns 2 when it should be 3. In fact it never outputs 3 at all, it skips straight to 4 at value =8. – pdeva Feb 12 '12 at 04:59
  • My apologies. The > signs should have been >= signs. I believe it should work now. – AHelps Mar 20 '12 at 17:18
4

For non-negative values, probably the most direct answer is:

java.math.BigDecimal.valueOf(value).bitLength()

(For negative numbers it will give the bit length of one less than the absolute value, rather than infinity you'd expect from two's complement notation.)

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • Not really *the bit length of the absolute value*: `System.out.println(BigInteger.valueOf(-1).bitLength());` prints 0, not 1 – Unai Vivi Aug 31 '12 at 14:33
  • @UnaiVivi Um yes. Corrected. It'd probably be better if the method threw `IllegalStateException` for negative values rather than doing something a bit strange. – Tom Hawtin - tackline Aug 31 '12 at 16:16
  • Do you have an idea why they did it that way (for negative numbers)? I can't see any usefulness the way they did it... – Unai Vivi Aug 31 '12 at 20:40
  • @UnaiVivi I believe if you add one you will get the minimum number of bits needed to represent the value in two's complement notation. – Tom Hawtin - tackline Sep 01 '12 at 15:45
1

I would like to add some other alternatives, just for the sake of completeness:

1 BigInteger.valueOf(i).bitLength()

Not very fast. Furthermore, BigInteger.bitLength() it's bugged and unreliable (fixed in Java7), since when more than Integer.MAX_VALUE bits are needed (freakishly high input number needed!! [such as 1 left-shifted Integer.MAX_VALUE times, aka 2^Integer.MAX_VALUE]) the result overflows and negative numbers appear for the next 2^(2*Integer.MAX_VALUE)-2^Integer.MAX_VALUE numbers, which is a number so high your head could explode. Note that it is estimated the universe containes some 10^80 atoms; that number is 2^4G (G as in Giga, 1024*1024*1024).

2

static int neededBits(int i)
{
    assert i > 0;
    int res;
    int sh;
    res = ((i > 0xFFFF) ? 1 : 0) << 4;
    i >>= res;
    sh = ((i > 0xFF) ? 1 : 0) << 3;
    i >>= sh;
    res |= sh;
    sh = ((i > 0xF) ? 1 : 0) << 2;
    i >>= sh;
    res |= sh;
    sh = ((i > 0x3) ? 1 : 0) << 1;
    i >>= sh;
    res |= sh;
    res |= (i >> 1);
    return res + 1;
}

A very fast solution, but still half as fast as ye olde 32 - Integer.numberOfLeadingZeros(i);.

Unai Vivi
  • 3,073
  • 3
  • 30
  • 46
1

Binary search over the the exponents of 2 is faster than the bit shift (top voted answer) solution, which might be valuable if the numbers are huge (thousands of decimal digits), you know the maximum available bits and you do not want to generate the tables:

    int  minExpVal   = 0;
    int  maxExpVal   = 62;
    int  medExpVal   = maxExpVal >> 1;
    long medianValue = 0l;

    while (maxExpVal - minExpVal > 1) {
        medianValue = 1l << medExpVal;
        if (value > medianValue) {
            minExpVal = medExpVal;
        } else {
            maxExpVal = medExpVal;
        }
        medExpVal = (minExpVal + maxExpVal) >> 1;
    }

    return value == 1l << maxExpVal ?  maxExpVal  + 1 : maxExpVal;

However, the solution using the leading zeros would be still by far faster:

return Long.SIZE - Long.numberOfLeadingZeros(value);

Benchmarks:

Leading zeros time is: 2 ms
BinarySearch time is: 95 ms
BitShift time is: 135 ms
Ilya K.
  • 153
  • 1
  • 9
1

This one works for me!

int numberOfBitsRequired(int n)
{
    return (int)Math.floor(Math.log(n)/Math.log(2)) + 1;
}

To include negative numbers as well, you can add an extra bit and use it to specify the sign.

public static int numberOfBitsRequiredSigned(int n)
{
    return (int)Math.floor(Math.log(Math.abs(n))/Math.log(2)) + 2;
}
Thiagesh thg
  • 100
  • 7
1

You can also do it like this, if you don't want to modify the original value.

unsigned int value = 11;
unsigned int count = 0;
if(value > 0)
{
    for(int i=1;i<value;i*=2) // multiply by two => shift one to left
    {
        ++count;
    }
}

Note: Let the compiler worry about turning i*=2 into a bit shift operation to improve performance.

For the visual thinkers among us:

64 32 16  8  4  2  1
 0  0  0  1  0  1  1  -> binary representation of decimal number 'value' = 11 (=1+2+8)

We start with i=1 at the right. Then we keep multiplying by two, for as long as i < value. In the meanwhile, we keep track of how many bits we went to the left.

So in this example, as soon as i reaches 16 the value is larger than 11, and thus we stop. And we will then have counted 4 bits: 1 *2 *2 *2 *2 = 16 (=2^4).

Careful with signed numbers. When dealing with signed numbers that may be positive or negative, you would first have to multiply the negative numbers by -1. Additionally, you would have to consider how you want to take the sign-bit into account.

Yeti
  • 2,647
  • 2
  • 33
  • 37
1

This is in C, but I suspect you could convert to Java fairly easily:

Find the log base 2 of an N-bit integer in O(lg(N)) operations

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
0

What about something like this:

public static int getNumberOfBits(int N) {
    int bits = 0;
        while(Math.pow(2, bits) <= N){
           bits++;
       }
       return bits;
}

I know you are looking for a way to not use loops, but I feel this is pretty strait forward otherwise since bits are just a two to the power of a number.

-1
(int) Math.ceil((Math.log(n) / Math.log(2))

Of course this only works for positive integers.