Подтвердить что ты не робот

Что означает "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.)

4b9b3361

Ответ 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, он работает не так.