Понимание правильного оператора сдвига со сдвигом бит - PullRequest
1 голос
/ 17 марта 2019

У меня проблемы с пониманием правильного оператора смены. Я понимаю левый сдвиг. Скажем, у нас нет

int n = 11; which is 1011

Теперь, если мы уйдем, сдвиньте его n << 1 Результат

int a = n << 1 ; so a = 10110; (simply add a 0 to the end)

Это имеет смысл

Теперь Правая смена - это то, где я испытываю трудности

int a = n >> 1

Я думаю, что ответом будет 01011 (добавьте 0 вперед), что будет снова 1011, но вместо этого 101. Мой вопрос: как мы потеряли последнюю цифру.

Обновление: Я могу предположить, что int будет 8-битным, в этом случае у нас будет int8 n = 1011 => который равен 00001011 поэтому, когда мы сдвигаемся вправо на 1, он превышает 8 бит на 1, поэтому последний бит сбрасывается, и он становится 0000101? Это понимание правильно?

Ответы [ 5 ]

7 голосов
/ 17 марта 2019

Похоже, вы неправильно понимаете, как работают смены.

Сдвиг не добавляет ноль влево или вправо.Вы не можете просто добавлять цифры, их так много.Давайте возьмем ваше число, десятичное число 11.

int n = 11;это 1011

Это правда, но это только половина истории.Смотрите, числа имеют фиксированный размер в вашем процессоре.Для целых чисел это 32 бита, но для упрощения предположим, что 8-битные числа.Ваш 11 выглядит так:

+-+-+-+-+-+-+-+-+
|0|0|0|0|1|0|1|1|
+-+-+-+-+-+-+-+-+

Он имеет 8 бит.Всегда.Теперь давайте сделаем сдвиг влево на 1:

 +-+-+-+-+-+-+-+-+
0|0|0|0|1|0|1|1| |
 +-+-+-+-+-+-+-+-+

После того, как вы сдвинулись, первый бит был «сдвинут».Там нет места для хранения этого бита.Кроме того, последний бит «пустой», мы не можем хранить «пустоту».Есть только один или ноль.Вместо этого мы «сдвигаем» нули.Таким образом, вы получите

+-+-+-+-+-+-+-+-+
|0|0|0|1|0|1|1|0|
+-+-+-+-+-+-+-+-+

При смещении вправо все наоборот.Мы снова начинаем с 11:

+-+-+-+-+-+-+-+-+
|0|0|0|0|1|0|1|1|
+-+-+-+-+-+-+-+-+

и сдвигаемся вправо на 1:

+-+-+-+-+-+-+-+-+
| |0|0|0|0|1|0|1|1
+-+-+-+-+-+-+-+-+

Снова, каждый бит сдвинут вправо на 1. Слева есть пустой бит, который,как и раньше, просто становится равным нулю.Справа вытащен, и нет места для его хранения.Это просто потеряно.Наше окончательное число:

+-+-+-+-+-+-+-+-+
|0|0|0|0|0|1|0|1|
+-+-+-+-+-+-+-+-+

Выше верно для чисел без знака, также называемых логическим смещением вправо .В системе с двумя дополнениями для чисел со знаком используется так называемое арифметическое смещение вправо , которое вместо смещения в нулевые биты сдвигается в знаковых битах.Т.е. если число отрицательное, следовательно, самый значимый бит равен единице, он сдвигается в единицу, в противном случае он сдвигается в ноль.

3 голосов
/ 17 марта 2019

Есть несколько способов взглянуть на это.

Во-первых, целочисленные числовые типы (в C, C ++, Java, C #) имеют фиксированное количество битов.Таким образом, 11 на самом деле (принимая редкий 8-битный int для удобства чтения):

 00001101 (8 digits)

Сдвиг влево на один бит

000011010 (9 digits?)

Но поскольку наше целое число может управлять только 8 битами, самый левый битпадает.

00011010 (8 digits)

То же самое происходит с 32-битными целыми числами: самый левый бит падает.

То же самое происходит со сдвигом вправо: бит справа падает.Если оригинал:

00011010 (8 digits)

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

00001101 (8 digits)

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

Обратите внимание, что с отрицательными числами все сложнее в C ++.Например, сдвиг влево отрицательного не определено

3 голосов
/ 17 марта 2019

1011 будет 101 после сдвига вправо. правый бит удален из 1011.

111110101 при смещении вправо на 3 дает 111110, удаляя жирные биты 111110 101

1 голос
/ 17 марта 2019

Вы не «потеряли» последнюю цифру. Вы просто не изменили то значение, о котором думали.

Вы начали с n = 0b1011. Вы сместили его влево на один бит и сохранили результат в a, оставив n без изменений. Затем вы сдвинули n (все еще со значением 0b1011) вправо и получили 0b0101.

Если бы вы сместили a вправо, а не n, вы бы увидели ожидаемый результат.

1 голос
/ 17 марта 2019

Скажем, у нас есть число (мы упростим его, скажем, 00010000), и мы хотим сдвинуть его влево, оно будет выглядеть так:

00010000 << 1 = 00100000

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

Со мной так далеко? хорошо.

Теперь, что делает сдвиг вправо? Что ж, он делает противоположное. Он помещает значение каждого столбца в столбцах x в его вправо . Например:

00010000 >> 1 = 00001000

Еще несколько более сложных примеров:

01010101 << 1 = 10101010
01010101 >> 1 = 00101010

11111111 << 2 = 11111100
11111111 >> 2 = 00111111

ПРИМЕЧАНИЕ: Сдвиги битов будут отсекать любые биты, которые сдвинуты по границе данных, как в примере 11111111, любые биты, которые падают за границы после потери сдвига.

...