2015-12-18 2 views
48

Что такое '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)

It должно привести к 0.3125.

Но, когда я бегу 5 << ~3, он приводит к 1342177280.

Что такое пошаговое объяснение? Как и почему эта комбинация операций приводит к 1342177280 вместо 0.3125?

(Этот вопрос похож на стек   переливных Question What are bitwise operators? об операторе побитового SHIFT.)

+5

Как может операция смены бит дать дробный результат, например 0,3125? – edc65

+0

@ edc65 Вот что я предполагаю, что ответ будет основан на базовом обучении 'XOR' и тильде' ~ '. Я абсолютно не понимаю, как это должно работать в любом случае. – choz

+9

после '! -' и '<< ~' что дальше? Я должен опубликовать сообщение «Что делает оператор'^< dhein

ответ

50

x << -n равен x << (32 - n)
~3 == -4 так
5 << ~3 === 5 << (32 - 4) === 5 << 28 которого 1,342,177,280

быть точными Х < < -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-битных целые числа

Как << operator работает

ОРЗ преобразуются в беззнаковое 32-битном целое число - как описано здесь ToUInt32

ToUint32 в основном принимает число и возвращает номер по модулю 2^32

+2

Как вы получаете ссылку, что '-n' равно' (32 - n) '? Я не сомневаюсь в том, что это Ответ: Но мне просто любопытно, потому что я не мог найти его. – choz

+6

@choz Это фактически полностью возвращается к компьютерной архитектуре. Это связано с тем, что в большинстве компьютерных инструкций используется 5 бит для хранения суммы сдвига (* по крайней мере для MIPS *). Особенно эти биты не подписаны двоичным. –

+0

Это не 32-n. Он использует только наименее сигнифицированные 5 бит, то есть 'n & 31' (см. цитированную ссылку об операторе <<, 12.8.3.11 подпункт 11). Если * n * отрицательно, тогда '32 + n' ==' n & 31' – edc65

7

~x будет возмещен битовым представление вашей значению х (32-битное значение с дополнением до два).

x << y является оператором сдвига влево (здесь слева). Ваша математическая интерпретация верна :)

Вы можете прочитать больше о поразрядных операциях здесь: bitwise operators in Javascript

6

5 << ~3 дает тот же результат, как 5 << -4, вы правы.

Важно одно: смещение х < < у действительно приводит к х * 2 у, но это не является прямым использование, это просто полезный побочный эффект.
Кроме того, если у вас есть отрицательный y, он не работает таким же образом.

+0

Как это должно работать с отрицательным значением btw? Мне жаль, что я действительно не понимаю, что такое бит. – choz

+1

*, если у вас есть отрицательный y, он не работает одинаково *, поэтому у вас фактически нет ответа на реальный вопрос. –

20

Оператор ~ переворачивает бит элемента, а << - побитовый сдвиг влево. Вот что происходит в двоичном порядке поэтапно. Обратите внимание, что большинство осталось немного быть 1 означал отрицательное число, этот формат twos compliment:

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 бит неподписанное целое число. Таким образом, двоичное число в двух комплиментах -4 (11100) unsigned будет 28.

+0

@JaromandaX. А ваше право, оно двоично 5, сдвинутое на -4. Дайте мне одну секунду, это объясняется тем, что кажется, что я выключен на 1. –

+0

Спасибо за ваш ответ spencer. Я использую онлайн-бинарный конвертер, который '00000111111111111111111111111111'' '0x07FFFFFF', который привел к' 134217727'. Я здесь что-то не так? – choz

+0

@choz Это было беспорядок с моей стороны, я прочитал последнее выражение в неправильном порядке и получил очень близкое число случайно. Я обновил свой ответ. –

9

Ваш анализ верен, за исключением того, что вы не должны интерпретировать ~ 3 (11100) (бит-дополнение 3 (00011)) как -4, а как неподписанное (то есть не- отрицательное) 5-битное целое число, а именно 28 = 16 + 8 + 4 (11100).

Это объясняется в ECMAScript standard (NB в большинстве современных машин, положительные и отрицательные целые числа представлены в памяти с помощью two's complement представления):

12.8.3 Левый сдвиг оператора (< <)

ПРИМЕЧАНИЕ Выполняет побитовое действие сдвига влево в левом операнде на величину, указанную правым операндом.

12.8.3.1 среды выполнения Семантика: Оценка

ВыражениеСдвига: ВыражениеСдвига < < АддитивноеВыражение

  1. Пусть LRef быть результатом оценки ВыраженияСдвига.
  2. Позвольте lval быть GetValue (lref).
  3. ReturnIfAbrupt (lval).
  4. Пусть rref будет результатом оценки AdditiveExpression.
  5. Пусть rval будет GetValue (rref).
  6. ReturnIfAbrupt (rval).
  7. Позвольте lnum быть ToInt32 (lval).
  8. ReturnIfAbrupt (lnum).
  9. Пусть rnum будет ToUint32 (rval).
  10. ReturnIfAbrupt (rnum).
  11. Пусть shiftCount является результатом маскировки всех, кроме наименее значимых 5 бит rnum, то есть вычисления rnum & 0x1F.
  12. Возвращает результат сдвига левой строки lnum битами shiftCount. Результатом является 32-битное целое число.
Смежные вопросы