Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does right shifting -1 always gives -1 in PHP?

I am trying to figure out why if I shift the negative integer -1 I always get -1, e.g.:

echo -1 >> 64; // -1
echo -1 >> 5; // -1
echo -1 >> 43; // -1
echo -1 >> 1; // -1

Whatever second operand of the right shift is given, -1 remains -1... I do understand that when you perform a right shift you're actually doing this:

x >> y = x / 2^y

But in the case of x being -1, if so, I do:

-1 >> 3 = -1 / 2^3

Shouldn't this value be -1/8 = -0.125?

Thanks for the attention.

like image 213
tonix Avatar asked Nov 08 '14 20:11

tonix


Video Answer


2 Answers

Bitwise shift operators don't divide. They do what they are supposed to do - shift bits. In particular, the right shift operator does the following:

  • for each bit starting from the right, set its value to what's on the left of it
  • for the leftmost bit, which has nothing on the left, keep its current value

For example, if your number is

1011...101

right shift gives you

11011...10

So the rightmost bit (LSB) is lost and the leftmost bit (MSB) is duplicated. This is called "sign propagation", because MSB is used to distinguish positive (MSB=0) from negative (MSB=1) numbers.

Negative numbers are stored as "two's complement", that is, on a 32-bit system, -x is stored as 2^32-x. So, -1 is 10...00 (32 zeroes) - 1 == 1...1 (32 ones). If you shift 32 ones according to the above procedure, you get 32 ones yet again, that is, -1 >> whatever will always be -1.

The difference between the right shift and division by two is that the shift gives same results for odd and even numbers. Since the rightmost bit is lost, when you shift an odd number (which has LSB=1), the result is the same as shifting the next lower even number (the same combination of bits, but with LSB=0). So, you get no halves when you shift, since the dividend is forced to be even. For example,

1010 = 10102, 10 / 2 = 5.0 and 10 >> 1 == 510 == 1012

1110 = 10112, 11 / 2 = 5.5 but 11 >> 1 == 510 == 1012

If you prefer to think about x >> 1 in terms of division, it first "rounds" x down to an even number (x - abs(x) % 2) and then divides that number by two.

For x = -1 this gives you (-1 - abs(-1) % 2)/2 == (-1 - 1)/2 = -2/2 = -1.

like image 155
georg Avatar answered Oct 21 '22 03:10

georg


It is the same in all languages I know - bitwise arithmetic right shift for -1 will be -1, and as others mentioned, this operation can be applied only to integers.

-1 is represented in binary as all bits filled with value 1. For arithmetic right shift the bits will be shifted to the right, and the highest bit (at the left) will be filled with sign of the value, for negative values it will be 1, and for positive - 0. So it makes -1 again after the shift.

There are other kinds of bitwise shifts, and for logical right shift the highest bit would be filled with zero. You can get some more info here: http://en.wikipedia.org/wiki/Bitwise_operation#Arithmetic_shift

like image 31
Mixaz Avatar answered Oct 21 '22 02:10

Mixaz