PHP’s bitwise operators <<
and >>
implement Arithmetic Bit Shifting. This means:
- Left shift (using
<<
operator) fills in zero(s) on the right end of the bitfield, and bit(s) shifted off the left end are discarded; - Right shift (using
>>
operator) discards bit(s) shifted off the right end of the bitfield and copy(ies) of sign bit are shifted in on the left end.
Logical Bit Shifting is different in that on right shifts, zeros are shifted in on the left end of the bitfield, affecting the sign of negative integer.
On 32 bit platforms, -2147483648
is the largest negative integer. Binary representation of this integer gives only the Most Significant Bit ON
and all other bits are OFF
. Shifting bits of this number $n
steps to the right would actually shift in $n
copies of the Most Significant Bit (or Sign Bit) and discard the same number of bits from the right.
$n = 30 echo decbin( -2147483648 ); // 10000000000000000000000000000000 //Arithmetic Right Shift echo decbin( -2147483648 >> $n ); // 11111111111111111111111111111110
The same is stated by PHP manual:
Bit shifting in PHP is arithmetic. Bits shifted off either end are discarded. Left shifts have zeros shifted in on the right while the sign bit is shifted out on the left, meaning the sign of an operand is not preserved. Right shifts have copies of the sign bit shifted in on the left, meaning the sign of an operand is preserved – PHP manual
Why Logical Right Shifting in PHP?
In php, bitwise operators are commonly used for manipulating colors, working with user permission management, character encoding/decoding etc and logical right shift is sometimes much needed to simplify operations. Many recommend its addition to php’s core and someone has even put up a request for comment for a new operator. No new operator is needed for Logical Left Shifts because logical and arithmetic left shift are the same.
Implementing logical right sift in PHP:
function logical_right_shift( $int , $shft ) { return ( $int >> $shft ) //Arithmetic right shift & ( PHP_INT_MAX >> ( $shft - 1 ) ); //Deleting unnecessary bits }
This function does not validate input. You have to make sure that both of the arguments $int
and $shft
are integer. Inappropriate arguments may cause unexpected results.
Tests
I have tested logical_right_shift
on 32 bit platform, specially with key cases:
0
where all 32 bits areOFF
;~ 0
or-1
where all 32 bits areON
;PHP_INT_MAX
– a positive integer with 31 bitsON
and just the sign bitOFF
, and;~ PHP_INT_MAX
– a negative integer (sign bitON
) with 31 bitsOFF
.
//Tested With $int = 0 ; //0, -1, PHP_INT_MAX, ~PHP_INT_MAX $shift = 5; echo 'INT: '.$int ."\n"; echo 'Before: '.substr(str_repeat('0',32).decbin($int),-32)."\n"; echo 'After: '.substr(str_repeat('0',32).decbin(logical_right_shift($int,$shift)),-32); //INT: 0 //Before: 00000000000000000000000000000000 //After: 00000000000000000000000000000000 //INT: -1 //Before: 11111111111111111111111111111111 //After: 00000111111111111111111111111111 //INT: 2147483647 //PHP_INT_MAX //Before: 01111111111111111111111111111111 //After: 00000011111111111111111111111111 //INT: -2147483648 //~ PHP_INT_MAX //Before: 10000000000000000000000000000000 //After: 00000100000000000000000000000000
Notes
logical_right_shift()
was tested to work fine with integers on 32 and 64 bit platforms. It should also work with strings (not tested).- Bitwise operators are high performance operators, often faster than arithmetic ones. You should not expect that high performance when using
logical_right_shift()
. - The function uses
PHP_INT_MAX
that is available since PHP 5.0.5.