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