манипуляция битами Java - PullRequest
       18

манипуляция битами Java

10 голосов
/ 19 февраля 2009
byte x = -1;
for(int i = 0; i < 8; i++)
{
    x = (byte) (x >>> 1);
    System.out.println("X: " + x);
}

Насколько я понимаю, java хранит данные в двоичном дополнении, что означает -1 = 11111111 (согласно википедии).

Кроме того, из документов Java: «Битовая комбинация задается левым операндом, а число позиций для смещения - правым операндом. Оператор правого сдвига без знака« >>> »сдвигает ноль в крайнюю левую позицию, а крайнюю левую позицию после ">>" зависит от расширения знака. "

Это означает, что >>> будет каждый раз сдвигать 0 влево. Поэтому я ожидаю, что этот код будет

итерация: битовое представление x

0: 11111111

1: 01111111

2: 00111111

3: 00011111

... и так далее

Однако мой вывод всегда X: -1, что означает (я полагаю), что >>> ставит бит знака в крайнее левое положение. Так что я тогда пытаюсь >> и тот же результат.

Что происходит? Я ожидаю, что мой результат будет: X: -1, x: 127, x: 63 и т. Д.

Ответы [ 5 ]

27 голосов
/ 19 февраля 2009

Кто бы ни думал, что байты должны быть подписаны, когда Java был изобретен, должен быть вынут и избит влажной палочкой сельдерея, пока они не кричат: -)

Вы можете делать то, что хотите, приводя к int и гарантируя, что вы никогда не сдвинете 1 в верхний бит, что-то вроде этого:

byte x = -1;
int x2 = ((int)x) & 0xff;
for(int i = 0; i < 8; i++)
{
    x2 = (x2 >>> 1);
    System.out.println("X: " + x2);
}

Ваша конкретная проблема заключается в том, что >>> выполняет приведение к int для сдвига, а затем возвращает его обратно в байт, как показано здесь:

byte x = -1;
int x2 = ((int)x) & 0xff;
int x3;
int x4 = x2;
for(int i = 0; i < 8; i++)
{
    x2 = (x2 >>> 1);
    System.out.println("X2: " + x2);
    x3 = (x >>> 1);
    x = (byte)x3;
    x4 = (x4 >>> 1);
    System.out.println("X: " + x3 + " " + x + " " + x4);
}

Какие выходы:

X2: 127
X: 2147483647 -1 127
X2: 63
X: 2147483647 -1 63
X2: 31
X: 2147483647 -1 31
X2: 15
X: 2147483647 -1 15
X2: 7
X: 2147483647 -1 7
X2: 3
X: 2147483647 -1 3
X2: 1
X: 2147483647 -1 1
X2: 0
X: 2147483647 -1 0

Вы можете ясно видеть, что x и x3 не работают (даже если x3 сдвигается правильно, приведение его к байту в x снова устанавливает его в -1). х4 работает отлично.

5 голосов
/ 19 февраля 2009

Помните, что:

  • операнды побитовые операции всегда повышаются до, по крайней мере, целых !
  • приведение всегда включает расширение знака .

Поэтому, когда вы делаете (x >>> n), даже если вы определили x как байт, для целей сдвига он сначала будет преобразован в int. Если преобразуемый байт является отрицательным, то все «лишние биты» (то есть 24 левые итоговые биты итогового значения), добавленные для его преобразования в целое число, будут установлены в 1. Или, если исходный, использовать другой путь байт был -1, то, что вы на самом деле сдвигаете, это -1 как int , то есть 32-битное число со всеми 32 битами, установленными в 1. Смещение этого права на 1-8 мест все равно приведет к младшие 8 битов все установлены в 1, следовательно, когда вы возвращаете обратно в байт, вы получаете байт со всеми 8 битами, установленными в 1, или, другими словами, байтовое значение -1. ​​

3 голосов
/ 19 февраля 2009

Я не уверен в этом. Но я думаю, что

x >>> 1 

повышается до int из байта, потому что литерал "1" является int. Тогда то, что вы наблюдаете, имеет смысл.

0 голосов
/ 24 ноября 2009

Проблема, как было сказано ранее (давным-давно), состоит в том, что x переводится в int (расширенный знак) перед выполнением смены. Выполнение преобразования "бит в бит" должно помочь:

byte x = -1;
for(int i = 0; i < 8; i++)
{
    x = (byte) ((x & 0xFF) >>> 1);
    System.out.println("X: " + x);
}
0 голосов
/ 19 февраля 2009

Я не знаю, почему это не работает, но простой способ очистить верхний бит - это (двоично)

x = (byte) (x >>> 1) & 0x7F;
...