Сдвиг влево с отрицательным счетчиком сдвига в Javascript

Вещь, которую я заметил в Javascript -

a << -1

Returns 0 when a = even.
Returns -2147483648 when a = odd.

Точно так же разные значения возвращаются, когда -1 изменяется на какое-либо другое -ve число. Может кто-нибудь объяснить, какие битовые операции происходят под капотом? Или поведение не определено?

Спасибо

ИЗМЕНИТЬ

Также не следует заполнять нулями правый сдвиг, т.е. -2 >>> 1 возвращать 7 ?

-2 = 1110. После сдвига вправо с заполнением нулями должно получиться 0111 = 7

но a = -2; console.log(a >>> 1); возвращает 2147483647


person kaustav datta    schedule 15.05.2013    source источник


Ответы (3)


Я тоже задавался вопросом об этом, поэтому я приземлился здесь. Я провел небольшое исследование и выяснил поведение. По сути, JavaScript обрабатывает операнд и значение сдвига как последовательности битов, а не как числа. Он работает с 32-битными целыми числами (число с плавающей запятой усекается), а максимальный сдвиг составляет 32 бита. Если мы сдвинемся на число больше 32, все биты сместятся, и в результате получится ноль. Чтобы гарантировать, что сдвиг меньше или равен 32, JavaScript усекает 5 младших значащих битов [a << (b&0x1F)] или, возможно, с помощью метода модуля [a << (b%32)], который дает тот же результат.

С учетом этого подумайте об отрицательном числе, на которое вы сдвигаетесь, как о последовательности битов, а не об отрицательном числе (т.е. -1). В данном случае b = -1 = 0xFFFFFFFF. Поскольку это число больше 32, оно усекается на 0xFFFFFFFF & 0x1F = 31 или 0xFFFFFFFF % 32 = 31.

Таким образом, в вашем примере «a» полностью смещается от младшего значащего бита до самого старшего бита (бит знака). Поэтому результатом сдвига является либо 0x00000000, либо (0x80000000 = -2147483648) в зависимости от того, был ли операнд 1 бит множество (нечетное или четное).

person Subskybox    schedule 21.03.2015

Получил ответ на вторую часть моего вопроса, т.е. -2 >>> 1 = 7.

Javascript всегда работает с 32 битами. Итак, когда я делаю -2 >>> 1, на самом деле под капотом происходит 11111111111111111111111111111110 >>> 1, что дает 01111111111111111111111111111111 = (2147483647)base10

person kaustav datta    schedule 15.05.2013

Оператор LeftShift добавляет нули справа от двоичного представления числа, сдвигая биты влево. Используются только 5 младших разрядов аддитивного выражения. Так:

var x = 5         // 101

alert( x << 1  ); // 1010 = 10

alert( x << 2  ); // 10100 = 20

alert( x << 3  ); // 101000 = 40

alert( x << 4  ); // 1010000 = 80

alert( x << 64 ); // 101 = 5

Последнее выражение возвращает 5, так как сдвиг использует только последние 5 бит аддитивного выражения, которое равно 1000000, поэтому используется только часть 00000.

person RobG    schedule 15.05.2013