Почему сдвиг вправо -1 всегда дает -1 в PHP?

Я пытаюсь понять, почему, если я сдвигаю отрицательное целое число -1, я всегда получаю -1, например:

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

Независимо от того, какой второй операнд правого сдвига задан, -1 остается -1... Я понимаю, что когда вы выполняете правый сдвиг, вы на самом деле делаете это:

x >> y = x / 2^y

Но в случае, если x равно -1, если это так, я делаю:

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

Разве это значение не должно быть -1/8 = -0,125?

Спасибо за внимание.


person tonix    schedule 08.11.2014    source источник
comment
целые числа, целые числа, целые числа.   -  person The Paramagnetic Croissant    schedule 08.11.2014
comment
Цитата из мануала (курсив мой): Bitwise operators allow evaluation and manipulation of specific bits within an __integer__.   -  person Mark Baker    schedule 08.11.2014
comment
о боже, серьезно... 5 плюсов? это должно быть кошмар!   -  person The Paramagnetic Croissant    schedule 09.11.2014


Ответы (2)


Операторы побитового сдвига не делят. Они делают то, что должны делать — сдвигают биты. В частности, оператор сдвига вправо делает следующее:

  • для каждого бита, начиная справа, установите его значение на то, что слева от него
  • для самого левого бита, у которого слева ничего нет, сохраните его текущее значение

Например, если ваш номер

1011...101

правый сдвиг дает вам

11011...10

Таким образом, самый правый бит (LSB) теряется, а самый левый бит (MSB) дублируется. Это называется распространением знака, потому что MSB используется для того, чтобы отличить положительные (MSB=0) от отрицательных (MSB=1) чисел.

Отрицательные числа хранятся в виде дополнения до двух, то есть в 32-битной системе -x хранится как 2^32-x. Итак, -1 равно 10...00 (32 zeroes) - 1 == 1...1 (32 ones). Если вы сдвинете 32 единицы в соответствии с описанной выше процедурой, вы снова получите 32 единицы, то есть -1 >> whatever всегда будет -1.

Разница между сдвигом вправо и делением на два заключается в том, что сдвиг дает одинаковые результаты для нечетных и четных чисел. Поскольку крайний правый бит теряется, при сдвиге нечетного числа (у которого LSB=1) результат будет таким же, как при сдвиге следующего меньшего четного числа (такая же комбинация битов, но с LSB=0). Таким образом, вы не получаете половин при сдвиге, так как делимое вынуждено быть четным. Например,

1010 = 10102, 10 / 2 = 5,0 и 10 ›› 1 == 510 == 1012

1110 = 10112, 11 / 2 = 5,5, но 11 ›› 1 == 510 == 1012

Если вы предпочитаете рассматривать x >> 1 с точки зрения деления, то сначала x округляется до четного числа (x - abs(x) % 2), а затем делится на два.

Для x = -1 это дает вам (-1 - abs(-1) % 2)/2 == (-1 - 1)/2 = -2/2 = -1.

person georg    schedule 08.11.2014

Это то же самое во всех известных мне языках - побитовый арифметический сдвиг вправо для -1 будет -1, и, как уже упоминалось, эту операцию можно применять только к целым числам.

-1 представляется в двоичном виде как все биты, заполненные значением 1. При арифметическом сдвиге вправо биты будут сдвинуты вправо, а старший бит (слева) будет заполнен знаком значение, для отрицательных значений это будет 1, а для положительных - 0. Таким образом, после сдвига он снова делает -1.

Существуют и другие виды побитовых сдвигов, и для логического сдвига вправо старший бит будет заполнен нулем. Дополнительную информацию можно получить здесь: http://en.wikipedia.org/wiki/Bitwise_operation#Arithmetic_shift

person Mixaz    schedule 08.11.2014