Вывод логического и арифметического сдвига

Вот крошечная программа на Java

public class otherclass {
public static void main(String[]args){
        byte a=-5;

        byte d= (byte) (a>>>1);
        System.out.println(d);
        byte e= (byte) (a>>>2);
        System.out.println(e);
        byte f= (byte) (a>>1);
        System.out.println(f);
        byte g= (byte) (a>>2);
        System.out.println(g);
}
}

вывод:

-3
-2
-3
-2

Вторые два выхода (те -3 и -2 логических сдвигов) я понимаю.

отрицательный 5 - 11111011

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

Логический сдвиг предполагает добавление нулей влево. 11111011 должно стать 01111101, что равно 125. Как он также выводит отрицательное 3?


person Mina Michael    schedule 31.03.2015    source источник
comment
Обратите внимание, что сдвиг происходит для значения типа int (4 байта).   -  person Sotirios Delimanolis    schedule 01.04.2015
comment
мммм, что ты имеешь в виду? Он не работает с байтовыми переменными?   -  person Mina Michael    schedule 01.04.2015
comment
это целочисленный тип, представленный определенным количеством байтов, определяемым типом. например, int имеет 32 байта. short - 16 байт, а byte - 8. Я тоже не понимаю комментарий @SotiriosDelimanolis.   -  person D. Ben Knoble    schedule 01.04.2015


Ответы (1)


Отсутствует информация о том, что Java продвигает значения к int при их битовом сдвиге, что называется бинарным числовым продвижением. Значения byte перед сдвигом повышаются до int, затем происходит сдвиг, затем они возвращаются к byte.

-5 as byte  : 11111011
-5 as int   : 11111111 11111111 11111111 11111011
Bit shifted : 01111111 11111111 11111111 11111101

Ноль сдвигается, но приведение обратно к byte все равно отбрасывает все, кроме последних 8 бит.

Cast to byte: 11111101 (-3)

Если вы хотите, чтобы операция >>> вела себя так, как если бы не было двоичного числового повышения, вы должны замаскировать последние 8 бит из повышенного int.

byte d= (byte) ((a & 0xFF)>>>1);
System.out.println(d);
byte e= (byte) ((a & 0xFF)>>>2);
System.out.println(e);

Вывод:

125
62

Что тут происходит:

-5 as byte  : 11111011
-5 as int   : 11111111 11111111 11111111 11111011
Bit masked  : 00000000 00000000 00000000 11111011
Bit shifted : 00000000 00000000 00000000 01111101

Ноль сдвигается, как и раньше, но приведение к byte все равно отбрасывает все, кроме последних 8 бит.

Cast to byte: 01111101 (125)

Обратите внимание, что это произойдет с >>> и с >>, поэтому выполняйте только битовые и с 0xFF в операциях >>>.

person rgettman    schedule 31.03.2015
comment
Я понимаю. Что ж, это ответ на вопрос. Спасибо за это. Но теперь мне нужно знать, как сделать сдвиг, не позволяя Java делать это продвижение. Я хочу сделать сдвиг байта как есть. - person Mina Michael; 01.04.2015
comment
Очень красивое объяснение! - person Alex Salauyou; 01.04.2015
comment
хе да ладно. Я понимаю, о чем вы говорите, только то, что впервые сталкиваюсь с маскировкой. Я думаю, мне нужно сначала узнать об этом немного. ... большое вам спасибо: D - person Mina Michael; 01.04.2015