2009-02-19 3 views
10
byte x = -1; 
for(int i = 0; i < 8; i++) 
{ 
    x = (byte) (x >>> 1); 
    System.out.println("X: " + x); 
} 

Как я понимаю, java хранит данные в 2'-дополнении, что означает -1 = 11111111 (согласно wikipedia).java bit манипуляция

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

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

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

0: 11111111

1: 01111111

2: 00111111

3: 00011111

. ..so on

Однако мой выход - alwa ys X: -1, что означает (я думаю), что >>> помещает бит знака в крайнее левое положение. Поэтому я затем попробую >>, и тот же результат.

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

+0

Это одна из проблем в Java Puzzlers. – starblue

ответ

27

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

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

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

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

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 

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

+0

хотя это работает (я ценю помощь), это не объясняет мне, почему мой код не работает. – jbu

+0

См. Обновление, которое объясняет это лучше. – paxdiablo

+0

Да, да, спасибо! – jbu

3

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

x >>> 1 

продвинут к междунар от байта, так как буквальный «1» является внутр. Тогда то, что вы наблюдаете, имеет смысл.

+0

Я так не думаю .. Я изменил код, чтобы убедиться, что он не получил повышение до int: байт x = -1; для (int i = 0; i <8; i ++) { x = (байт) ((байт) x >> (байт) 1); System.out.println ("X:" + x); } Выход был тот же, X: -1 каждый раз – jbu

+0

Это не помогает - уверен, вы конвертируете x и 1 в байты, но Java автоматически преобразует их обратно в int перед применением оператора сдвига справа. Насколько я знаю, нет возможности напрямую применять бит-сдвиг к байтам. –

0

Я не знаю, почему он не работает, но простой способ очистить верхнее бит является & с (двоичным) 0111111:

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

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

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

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

0

Проблема заключается в том, что, как говорилось ранее (давным-давно), x ускоряется до int (sign-extended) перед выполнением сдвига.
Выполнение «бит в бит» преобразование должно помочь:

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

было бы интересно узнать, почему -1 ... –

Смежные вопросы