Что означает "x << ~ y" в JavaScript?
Что означает 'x < < ~ y 'представляют в JavaScript?
Я понимаю, что побитовая операция SHIFT
делает это:
x << y AS x * 2y
И оператор тильды ~
:
~x AS -(x+1)
Итак, я предполагаю следующее:
5 << ~3 AS 5 * 2-4 or 5 * Math.pow(2, -4)
Это должно привести к 0.3125
.
Но, когда я запускаю 5 << ~3
, это приводит к 1342177280
.
Что такое пошаговое объяснение? Как и почему эта комбинация операций приводит к 1342177280
вместо 0.3125
?
(Этот вопрос похож на Stack вопрос с переполнением Что такое побитовые операторы? относительно побитового оператора SHIFT
.)
Ответы
Ответ 1
x << -n
равно x << (32 - n)
~3 == -4
так что
5 << ~3
=== 5 << (32 - 4)
=== 5 << 28
, который 1,342,177,280
чтобы быть точным X < -n не совпадает с X < (32 - n)... на самом деле он и более простой, и более сложный... допустимый диапазон оператора сдвига битов равен 0... 31... RHS в операторе сдвига бит сначала преобразуется в неподписанное 32-битное целое число, затем замаскировано 31 (шестнадцатеричный 1f) (двоичный 11111
)
3 = 00000000000000000000000000000011
~3 = 11111111111111111111111111111100
0x1f (the mask) 00000000000000000000000000011111
--------------------------------
~3 & 0x1f 00000000000000000000000000011100 = 28
когда величина меньше 32, она точно такая же, как и выше, чем
Операции бит работают с 32-битными целыми числами. Отрицательные сдвиги бит бессмысленны, поэтому они переносятся на положительные 32-битные целые числа.
Как < оператор работает
Преобразование rhs в неподписанное 32-битное целое число - как описано здесь ToUInt32
ToUint32 в основном принимает число и возвращает число по модулю 2 ^ 32
Ответ 2
Оператор ~
переворачивает биты элемента, а <<
- побитовый сдвиг влево. Вот что происходит в двоичном порядке поэтапно. Обратите внимание, что самый левый бит, равный 1, обозначает отрицательное число, этот формат двухкомпонентный комплимент:
3 // (00000000000000000000000000000011 => +3 in decimal)
// ~ flips the bits
~3 // (11111111111111111111111111111100 => -4 in decimal)
// The number 5 (..00101) shifted by left by -4 (-4 unsigned -> 28)
5 // (00000000000000000000000000000101 => +5 in decimal)
5 << -4 // (01010000000000000000000000000000 => +1342177280 in decimal)
В последней строке биты смещаются и "вращаются" на другую сторону, что приводит к большому положительному числу. Фактически смещение на отрицательное число похоже на побитовое вращение (переполненные биты повернуты на другую сторону), где сдвиг по положительным числам не имеет такого поведения. Откат состоит в том, что невращающиеся биты игнорируются. Существенно, что 5 << -4
совпадает с тем, что делает 5 << (32 - 4)
, что скорее поворот на самом деле является большим сдвигом.
Причиной этого является то, что сдвиги бит - это всего лишь 5-битное целое число без знака. Таким образом, двоичное число в twos compliment -4 (11100)
unsigned будет 28
.
Ответ 3
Ваш анализ верен, за исключением того, что вы не должны интерпретировать ~ 3 (11100) (бит-дополнение 3 (00011)) как -4, но как 5-разрядное целое число без знака (то есть неотрицательное) а именно 28 = 16 + 8 + 4 (11100).
Это объясняется в стандарте ECMAScript (NB) в большинстве современных машин, положительные и отрицательные целые числа представлены в память, используя два дополнения):
12.8.3 Оператор сдвига влево (<)
ПРИМЕЧАНИЕ Выполняет побитовую операцию сдвига влево в левом операнде на величину, указанную правым операндом.
12.8.3.1 Семантика времени выполнения: оценка
ShiftExpression: ShiftExpression < < < АддитивноеВыражение
- Пусть lref является результатом вычисления выражения Shift.
- Пусть lval - GetValue (lref).
- ReturnIfAbrupt (lval).
- Пусть rref является результатом оценки AdditiveExpression.
- Пусть rval - GetValue (rref).
- ReturnIfAbrupt (RVAL).
- Пусть lnum - ToInt32 (lval).
- ReturnIfAbrupt (lnum).
- Пусть rnum - ToUint32 (rval).
- ReturnIfAbrupt (rnum).
- Пусть shiftCount является результатом маскировки всех, кроме наименее значимых 5 бит rnum, то есть вычисления rnum и 0x1F.
- Возвращает результат сдвига левой строки lnum по битам shiftCount.
результатом является подписанное 32-разрядное целое число.
Ответ 4
~x
изменит представление битов вашего значения x (32-битное знаковое значение с двумя дополнениями).
x << y
- оператор сдвига слева (здесь слева). Ваша математическая интерпретация верна:)
Подробнее о побитовых операциях вы можете прочитать здесь: побитовые операторы в Javascript
Ответ 5
5 << ~3
дает тот же результат, что и 5 << -4
, вы правы.
Важное замечание: сдвиг x < y действительно приводит к x * 2 y, но это не прямое использование, это просто полезный побочный эффект.
Более того, если у вас есть отрицательный y
, он работает не так.