Автор: Widowmaker1984

Вопрос 15 (побитовые операции)

"Какая арифметическая операция выполняется при побитовом сдвиге вправо/влево?"

1. Для целых числовых типов данных — long, int, short, char и byte, определен дополнительный набор операторов, с помощью которых можно проверять и модифицировать состояние отдельных битов соответствую­щих значений. В таблице приведена сводка таких операторов. Операторы битовой арифметики работают с каждым битом как с самостоятельной величиной. Предположим, если a = 60; и b = 13; то в двоичном формате они будут следующие:
a = 0011 1100
b = 0000 1101

2. Список побитовых операций (без вариаций с присвоением):
~ (побитовое унарное отрицание (NOT))
&(побитовое И (AND))
| (побитовое ИЛИ (OR))
^ (побитовое исключающее ИЛИ (XOR))
>> (сдвиг вправо)
<< (сдвиг влево)
>>> (сдвиг вправо с заполнением нулями)

скрытый текст2.1. Примеры выполнения побитовых операций:
a&b = 0000 1100
a|b = 0011 1101
a^b = 0011 0001
~a = 1100 0011

3. Оператор << выполняет сдвиг влево всех битов своего левого операнда на число позиций, заданное правым операндом. При этом часть битов в левых разрядах выходит за границы и теряется, а соответствующие правые позиции заполняются нулями.

3.1.При применении оператора сдвига влево к операнду типа int биты теряются, как только они сдвигаются за пределы 31 позиции. Если операнд имеет тип long, биты теряются после сдвига за пределы 63 позиции.

3.2. Автоматическое повышение типа, используемое в Java, может привести к странным результатам при выполнении сдвига в значениях типа byte, short. При вычислении выражений тип значений byte и short повышается до типа int. Это означает, что результатом выполнения сдвига влево значения типа byte или short будет значение int, и сдвинутые влево позиции не будут отброшены до тех пор, пока они не будут сдвинуты за пределы 31 позиции. Более того, при повышении до типа int отрицательное значение типа byte или short получит дополнительный знаковый разряд. Следовательно, старшие биты будут заполнены единицами. Поэтому при выполнении сдвига влево в значении типа byte сначала будет повышение до типа int и лишь затем сдвиг. Поэтому для получения требуемого сдвинутого значения типа byte необходимо отбросить три старших байта результата. Простейший способ достижения этого - обратное приведение результата к типу byte.

byte x = 64;
byte y;
int i;
i = x << 2; // сдвиг влево
y = (byte) (x << 2); // сдвиг влево с приведением

Результат:
i равно: 256
y равно: 0

Поскольку для выполнения вычислений тип переменной повышается до int, сдвиг влево на две позиции значение 64 (0100 0000) приводит к значению 256 (1 0000 0000). Однако, переменная y содержит значение не 256, а 0, поскольку после сдвига крайний единичный бит оказывается сдвинутым за пределы допустимого диапазона.

3.3. Приёмом сдвига влево часто пользуются в программах, где происходит много сложных вычислений. По сути, это замена операции умножения на 2, которая в силу особенностей процессора гораздо эффективнее. Но при этом следует соблюдать осторожность, так как при сдвиге единичного бита в старшую позицию (бит 31 или 63) значение становится отрицательным.

4. Оператор >> означает сдвиг вправо. Он перемещает все биты своего левого операнда вправо на число позиций, заданное правым операндом. Когда биты левого операнда выдвигаются за самую правую позицию слова, они теряются. При сдвиге вправо освобождающиеся старшие (левые) разряды сдвигаемого числа заполняются предыдущим содержимым знакового разряда. Такое поведение называют расширением знакового разряда, из-за него знаки отрицательных чисел сохраняются при сдвиге.

4.1. Примеры выполнения операций сдвига:
A << 2 равно 0011 1100 << 2 равно 1111 0000 равно 240
A >> 2 равно 0011 1100 >> 2 равно 0000 1111 равно 15

4.2. Иногда требуется, чтобы при сдвиге вправо расширение знакового разряда не происходило, а освобождающиеся левые разряды просто заполнялись бы нулями. Для этого используется оператор >>>:

int x = -17, z1, z2;
// x: 11111111 11111111 11111111 11101111
z1 = x >> 2;
// z1 = -5: 11111111 11111111 11111111 11111011
z2 = x >>> 2;
// z2 = 1073741819 : 00111111 11111111 11111111 11111011

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

4.3.1. Обратите внимание, что результат сдвига вправо значения -1 всегда равен -1, поскольку дополнительные знаковые разряды добавляют новые единицы к старшим битам.

5. Как и бинарные арифметические операторы побитовые операции имеют составные формы, которые объединяет побитовый оператор с оператором присваивания.

&=(побитовое И (AND) с присваиванием)
|= (побитовое ИЛИ (OR) с присваиванием)
^= (побитовое исключающее ИЛИ (XOR) с присваиванием)
>>= (сдвиг вправо с присваиванием)
<<= (сдвиг влево с присваиванием)
>>>= (сдвиг вправо с заполнением нулями с присваиванием)

Комментарии


Лучшее   Правила сайта   Вход   Регистрация   Восстановление пароля

Материалы сайта предназначены для лиц старше 16 лет (16+)