I need the ability to identify the index of each set bit (value=1) in a Redis bitfield. I found this which suggests using the bitpos
function but there’s a problem. As far as I can tell it takes the start of the range with a byte level specificity so if there’s multiple set bits in a given byte I can only see the first set bit within that byte. Alternatively I could grab the entire value but I’m getting incorrect answers when I do this (my code is in PHP).
$temp = $redis_conn->getRange('mykey', 0, -1);
$output = "";
for($i=0;$i < strlen($temp); $i++) {
$up = unpack('H*', $temp[$i]);
$bc = base_convert($up[1], 16, 2);
if($bc == '0') {
$bc = '00000000';
}
$output .= $bc;
}
for($i = 0; $i < strlen($output); $i++) {
if($output[$i] == '1') {
echo ($i+1).PHP_EOL;
}
}
I think this code should work but the answers are wildly incorrect. I put a check in for a one character string because when all 8 digits should’ve been 0 the base_convert only gave me one digit back throwing the indices way off. Looking through I can see that there are other places where the result of base_convert
is not 8 digits which can account for a lot of the mismatch between expected and actual results but not all of it. Does anyone know of a good way to get either of these methods to work? Either the bitpos
command or converting the binary after pulling down the entire bitfield?
EDIT: As an example I told it to set the bits at indices 12921, 72312 and 74616. I have 12921 coming out as expected but the highest index I’m seeing is 73623.
Advertisement
Answer
Sounds like you are always expecting it to produce 8 characters from base_convert()
, but it will only provide enough digits to represent the number.
You can pad the number with leading 0’s to make sure it’s always 8 chars using str_pad()
and STR_PAD_LEFT
to left pad the string…
$output .= str_pad($bc, 8, "0", STR_PAD_LEFT);