Поведение беззнакового правого сдвига, примененного к байтовой переменной - PullRequest
22 голосов
/ 16 октября 2010

Рассмотрим следующий фрагмент кода Java

byte b=(byte) 0xf1;
byte c=(byte)(b>>4);
byte d=(byte) (b>>>4);

выход:

c=0xff
d=0xff

ожидаемый результат:

c=0x0f

как? как б в двоичном 1111 0001 после беззнакового сдвига вправо 0000 1111 отсюда 0x0f но почему 0xff как?

Ответы [ 6 ]

38 голосов
/ 16 октября 2010

Проблема в том, что все аргументы сначала переводятся в int до того, как произойдет операция сдвига:

byte b = (byte) 0xf1;

b подписано, поэтому его значение равно -15.

byte c = (byte) (b >> 4);

b сначала расширяется до целого числа -15 = 0xfffffff1, затем смещается вправо до 0xffffffff и усекается до 0xff путем приведения к byte.

byte d = (byte) (b >>> 4);

b сначала расширяется до целого числа -15 = 0xfffffff1, затем смещается вправо до 0x0fffffff и усекается до 0xff путем приведения к byte.

Вы можете сделать (b & 0xff) >>> 4, чтобы получить желаемый эффект.

4 голосов
/ 16 октября 2010

Я предполагаю, что b - это знак, расширенный до int перед сдвигом.

Так что это может работать как ожидалось:

(byte)((0x000000FF & b)>>4)
1 голос
/ 16 октября 2010

Согласно Операции побитового и битового сдвига :

Оператор сдвига вправо без знака ">>>" переводит ноль в крайнее левое положение, а крайнее левое положение после ">> "зависит от расширения знака.

Таким образом, с b >> 4 вы преобразуете 1111 0001 в 1111 1111 (b отрицательно, поэтому он добавляет 1), то есть 0xff.

0 голосов
/ 28 февраля 2019

байт b = (байт) 0xf1;

если (b <0) </p>

d = (байт) ((байт) ((байт) (b >> 1) & (байт) (0x7F)) >>> 3);

иначе

d = (байт) (b >>> 4);

Сначала проверьте значение: Если значение отрицательное. Сделайте одно правое смещение, затем & 0x7F, оно будет изменено на положительное тогда вы можете легко сделать остаток правого сдвига (4-1 = 3).

Если значение положительное, сдвиг вправо с помощью >> 4 или >>> 4. Не имеет значения ни результат, ни проблема смещения вправо.

0 голосов
/ 25 февраля 2019

Операнд байта переводится в int перед сдвигом.

См. https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.19

Унарное числовое продвижение (§5.6.1) выполняется для каждого операнда отдельно.(Двоичное числовое продвижение (§5.6.2) не выполняется для операндов.)

И https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.1

В противном случае, если операнд имеет время компиляциитип byte, short или char, он повышается до значения типа int путем расширяющегося примитивного преобразования (§5.1.2).

0 голосов
/ 16 октября 2010

Java пытается экономить на явной поддержке базовых типов без знака, определяя вместо этого два различных оператора сдвига.

Вопрос говорит о беззнаковом сдвиге вправо, но примеры делают и (подписанный, и беззнаковый) и показывают значение подписанного сдвига (>>).

Ваши вычисления будут правильными для беззнакового смещения (>>>).

...