views:

267

answers:

8

I need to find the highest order 1 in some longs, ints, and shorts in Java. For example, if I had a char that looked like 00110101, I need a method that will return 2 (index of highest order 1).

Now, I know that you can do this using a for loop like:

for(int i=0; i<8; i++)
    if((x & 1<<i) != 0) return i;
return -1;

but this is way slower than what I want to do. I know modern CPUs have instructions that do this on chip, so I want to know how I can make a call to that rather than having an explicit loop.

EDIT: Bonus points if you can just return the indices of all of the ones in the primitive.

Thanks.

+2  A: 

Integer.highestOneBit(i); this would return 5 if you pass 00110101b into it.

if you've accidentally flipped the order of bits in your example, and you want a method that returns 2, then it is Integer.lowestOneBit(i);

Buhb
I don't know about this. At first, I thought it was the solution, but highestOneBit doesn't return the value the OP is asking about. They'd still have to do bit masking to find the actual position (although if the bit position is just an intermediate value in the OPs problem, maybe highestOneBit will get them exactly what they are looking for)
Kevin Day
highestOneBit() does return what he's asking for sort of but I think the original poster is indexing his binary "array" backwards from normal convention. If bit 2 is the highest order bit in his example then bit 0 must be what we'd normally call the 7th bit (and it's a value of 0 in this case) versus normal bit 0 (which is a one in his case). If the original poster really wants to index backwards then the math is simple: index = 7 - Integer.highestOneBit(i)
PSpeed
Though after actually looking at the javadocs ;) highestOneBit() actually returns the bit itself... not the index. I get what @Keven is saying now. numberOfLeadingZeros is what the OP wants, I think... as per another response.
PSpeed
A: 

I don't know about hitting a CPU instruction, but I do know that this will be a lot faster if you unroll the loop and use explicit bit masking.

Also, a char is not 8 bits... I think you might have meant a byte.

Kevin Day
I was thinking of C style char's (they're 8 bits right?...). Are Java's chars are 2 bytes for unicode support?
twolfe18
Yeah, they are.
Carl Smotricz
+2  A: 

The page "Bit Twiddling Hacks" contains lots of bit hacks. One is how to find the index of the highest order bit.

Aaron Digulla
I used to use these algorithms in my Java code, but most of them have been added to the platform API in the last few years.
finnw
However the de Bruijn sequence method is still marginally faster than the divide-and-conquer method used in the built-in `numberOfLeadingZeros` and `numberOfTrailingZeros`.
finnw
A: 

As far as I can tell, the Pentium and friends don't have an instruction ready-made for this. So the thing to do is to use a decent algorithm.

The key to getting your answer quickly is to use a binary search. You're looking at a long with 64 bits? 6 comparisons will give you your highest bit, every time.

The code works out to a big ugly tree of 64 if statements, but only a fraction of those will ever be executed, so runtime is good.

If you need sample code, I can do that. But I'd rather not.

Carl Smotricz
It need not be expressed using a tree, see my answer.
meriton
As I commented, I like the elegance of the code but I doubt its performance is acceptable.
Carl Smotricz
+2  A: 

Integer.numberOfLeadingZeros(i) + 1

That method uses a nice divide-and-conquer approach, copied here for your review:

public static int numberOfLeadingZeros(int i) {
    // HD, Figure 5-6
    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;
}
meriton
The algorithm is elegant, but shifting is horribly slow AFAIK.
Carl Smotricz
Better to shift 8 times (worst case), than 32, like generalizing the loop from the question would. (And that is assuming the JIT-Compiler unrolls the loop, otherwise the branch overhead would dominate.
meriton
Is there a reference for shifting being "horribly slow" in Java? I've never heard that.
PSpeed
+1  A: 

I have no idea if this is faster. But it has no loop.

if(i==0) return -1;

highest=0;
if (i & 0xffff0000)
{
   highest+=16;
   i>>=16;
}
if (i & 0xff00)
{
   highest+=8;
   i>>=8;
}
if (i & 0xf0)
{
   highest+=4;
   i>>=4;
}
if (i & 0xC)
{
   highest+=2;
   i>>=2;
}
if (i & 0x2)
{
   highest+=1;
}

return highest;
yu_sha
A: 

Java being compiled into platform-independent bytecode, you cannot expect support for CPU instructions. Otherwise your code or Integer.highestOneBit() should be as fast as it gets.

FelixM
well, i agree in principle, but i think java does do some things in platform dependent ways (for efficiency), but they fall back on a java implementation if the platform is not cooperative. i was hoping this was one of them...
twolfe18
Of course the JVMs are platform-specific, but for your case the JIT compiler would have to detect your true intention from the bytecode, which may be difficult. But if speed is of the essence, you might consider using platform-independent assembler, i.e. a C library and JNI.
FelixM
A: 

Is it something like this you're after?

System.out.println("00110101".indexOf("1"));
Kennet
:) ... i wish, but no
twolfe18
haha - that's pretty funny. Reminds me of a programmer I had on staff one time who converted a number to a string so he could round it. Oy.
Kevin Day