I know I can write the following method to calculate the set bit indexes of a long :
private static List<Integer> bitPositions(long number) {
final List<Integer> positions = new ArrayList<>();
int position = 1;
while (number != 0) {
if ((number & 1L) != 0) {
positions.add(position);
}
position++;
number = number >>> 1;
}
return positions;
}
My question is : Is there a faster method to do this ?
Fastest method
BitBank's answer to this question is about twice as fast as this answer's two methods just below this one. This steals the idea in BitBank's answer and makes it about 73% faster than it on my machine (9 times faster than the question's method) by using bit twiddling to repeatedly turn off the least-significant one bit rather than right-shifting the one bit off the right end and keeping track of how much shifting has occurred.
Improvements on BitBank's answer
byte
speeds things up slightly. I assume this is because it allows forbyte
-sized rather thanint
-sized arithmetic.Manual fusion
As Durandal pointed out in the question's comments, you can trade the following:
for a style that skips the method call and does this instead:
Benefits of fusion
Drawbacks of fusion
If you want to iterate multiple separate times through the bit positions of the same number, you have to compute the bit positions over again rather than reusing a previously generated array.
This might not be an actual drawback, though, if computing a bit position anew is quicker than loading a precomputed one from an array in RAM.
Slowest method
Here's a method that produces the same results (just in a
byte[]
instead of aList<Integer>
) about twice as fast:I'd recommend changing
byte bit = 1
in thefor
loop tobyte bit = 0
to switch to the traditional method of numbering bit positions starting with zero instead of one.Improvements
Long.bitCount(n)
(uses the very speedy "popcount" instruction of your processor) speeds up your method quite a bit. You can change this by making theArrayList
usingnew ArrayList<>(Long.bitCount(n))
.ArrayList<Integer>
is slower than abyte[]
, because:-127
to128
)Integer
values from theInteger
cache to put them into theArrayList
.int
s stored in the resultingList<Integer>
later on because you have to both retrieve theInteger
from theList<Integer>
and then retrieve theint
from theInteger
.byte[]
uses about 1/4th (32-bit system) or 1/8th (64-bit system) the memory of anArrayList<Integer>
, sincebyte
s are that much smaller than pointers toInteger
s.Slightly faster than slowest method, but uglier
As suggested by another person's deleted answer, loop unrolling speeds things up a little bit further on my machine (check whether that's true on your machine as well):
You can also change this to start counting the bit positions at zero instead of one.
Improvements
>>>
on the number.++
on the bit positon.