Разница между >>> и >>

Ответы:

408

>>арифметический сдвиг вправо, >>>логический сдвиг вправо.

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

Например: -2, представленный в 8 битах, будет 11111110(потому что старший значащий бит имеет отрицательный вес). Сдвиг вправо на один бит с использованием арифметического сдвига даст вам 11111111или -1. Логическое смещение вправо, однако, не заботится о том, чтобы значение могло представлять число со знаком; он просто перемещает все вправо и заполняет слева нулями. Сдвиг нашего -2 правильного бита с использованием логического сдвига даст 01111111.

danben
источник
8
Хотя я согласен и ценю, что арифметические сдвиги могут быть использованы для умножения чисел со знаком на 2^k, я нахожу странным, что это ответ каждого. Строка битов не является числом и >>всегда может использоваться с любой строкой битов: она всегда выполняет одно и то же, независимо от роли, которую играет строка битов, и независимо от того, имеет ли она понятие «знак». Было бы хорошо дополнить ваш и без того отличный ответ обсуждением случая, когда ваш операнд не интерпретируется как число со знаком? Имеет ли смысл моя жалоба?
Зигги
11
Почему вы говорите, что строка битов не является числом? Вы сказали бы, что последовательность десятичных цифр не является числом?
Данбен
4
@danben Обсуждение, является ли оно числом или нет, имеет смысл только в том случае, если вы связываете его с контекстом. Если интернет - это просто электричество, тогда я согласен, что String - это просто число.
bvdb
1
@danben, но на самом деле, я думаю, что Зигги действительно имел в виду (imho), что a Stringтакже может рассматриваться как a char[]. Он не говорит, что это charне число; он просто говорит, что это число без знака . Я думаю, что там он и потерян.
bvdb
5
@ Зигги прав: не каждая строка битов является числом, и не каждая последовательность десятичных цифр является числом. Например: телефонные номера, почтовые индексы (во многих странах) и т. Д. Являются строками десятичных цифр, но не имеет смысла их добавлять, вычитать или умножать, поэтому они не являются на самом деле числами. Это строки десятичных цифр, но их следует рассматривать как строки символов. (Почтовые коды в Канаде и Великобритании содержат буквы и цифры.)
jcsahnwaldt говорит GoFundMonica
102

>>>беззнаковая смена; это вставит 0. >>подписано, и расширит бит знака.

JLS 15.19 Операторы сдвига

Операторы сдвига включают сдвиг влево, сдвиг <<вправо со знаком >>и сдвиг вправо без знака >>>.

Значение n>>sявляется nправой сдвинутые sбитовые позиции с знаком-расширения .

Значение n>>>sявляется nправой сдвинутые sбитовые позиции с нулевым расширением .

    System.out.println(Integer.toBinaryString(-1));
    // prints "11111111111111111111111111111111"
    System.out.println(Integer.toBinaryString(-1 >> 16));
    // prints "11111111111111111111111111111111"
    System.out.println(Integer.toBinaryString(-1 >>> 16));
    // prints "1111111111111111"

Чтобы сделать вещи более понятными, добавив положительный аналог

System.out.println(Integer.toBinaryString(121));
// prints "1111001"
System.out.println(Integer.toBinaryString(121 >> 1));
// prints "111100"
System.out.println(Integer.toBinaryString(121 >>> 1));
// prints "111100"

Поскольку это положительные сдвиги как со знаком, так и со знаком без знака, к левому биту будет добавлено 0.

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

polygenelubricants
источник
Без твоих примеров я бы этого не понял.
mr5
47

Они оба сдвига вправо, но >>>этоunsigned

Из документации :

Оператор смещения вправо без знака «>>>» смещает ноль в крайнее левое положение, а крайнее левое положение после «>>» зависит от расширения знака.

Matt
источник
12
Вы можете объяснить на примере
Касун Сиямбалапития,
1
Я также думаю, что вы должны привести пример.
byxor
Я полагаю, что >>>это без знака, но почему 7>>32=7? Я запустил цикл, который делал по одной смене за раз, и увидел, что после 32смен он вернулся 7. Единственный способ, которым это может иметь смысл, состоит в том, что для каждого смещенного числа оно входит во «внешний круг». После 32смены он каким-то образом вернулся к своей позиции, но, очевидно, это все еще не имеет смысла. Что здесь происходит?
Ян Лимарта
@IanLimarta Это не так? Я просто получаю 0. ( for (int i = 7 << 1, j = 0; j < 32; j++) System.out.println(Integer.toString(i >>= 1, 2));) Если вы имеете в виду, почему >>32сам возвращает исходное значение, посмотрите это .
Мойра
Мне жаль. Я имел в виду, почему «7 >>> 32 = 7».
Ян Лимарта
40

Логическое правое смещение ( v >>> n) возвращает значение, в котором биты vсдвинуты вправо на nбитовые позиции, а 0 сдвинуты с левой стороны. Рассмотрим смещение 8-битных значений, записанных в двоичном виде:

01111111 >>> 2 = 00011111
10000000 >>> 2 = 00100000

Если мы интерпретируем биты как неотрицательное целое число без знака, логический сдвиг вправо приводит к делению числа на соответствующую степень, равную 2. Однако, если число находится в представлении с двумя дополнительными числами, логическое смещение вправо неправильно делит отрицательные числа. , Например, второй правый сдвиг выше сдвигает от 128 до 32, когда биты интерпретируются как числа без знака. Но он сдвигается от -128 до 32, когда, как это обычно бывает в Java, биты интерпретируются как дополнение к двум.

Следовательно, если вы сдвигаетесь, чтобы делить на степень два, вам нужен арифметический сдвиг вправо ( v >> n). Он возвращает значение, в котором биты vсмещены вправо на nбитовые позиции, а копии самого левого бита v смещены с левой стороны:

01111111 >> 2 = 00011111
10000000 >> 2 = 11100000

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

Andru
источник
38

>>>всегда будет ставить 0 в крайнем левом бите, а >>1 или 0 - в зависимости от того, что это за знак.

corsiKa
источник
10

Узнайте больше о побитовых и битовых операторах

>>      Signed right shift
>>>     Unsigned right shift

Битовая комбинация задается левым операндом, а число позиций для смещения - правым операндом. Оператор смещения вправо без знака >>> сдвигает ноль в крайнее левое положение ,

в то время как крайнее левое положение после >>зависит от расширения знака.

Простыми словами >>>всегда смещает ноль в крайнее левое положение, тогда как >>смещения основаны на знаке числа, то есть 1 для отрицательного числа и 0 для положительного числа.


Например, попробуйте как с отрицательными, так и с положительными числами.

int c = -153;
System.out.printf("%32s%n",Integer.toBinaryString(c >>= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c <<= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c >>>= 2));
System.out.println(Integer.toBinaryString(c <<= 2));

System.out.println();

c = 153;
System.out.printf("%32s%n",Integer.toBinaryString(c >>= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c <<= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c >>>= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c <<= 2));

вывод:

11111111111111111111111111011001
11111111111111111111111101100100
  111111111111111111111111011001
11111111111111111111111101100100

                          100110
                        10011000
                          100110
                        10011000
Braj
источник
Спасибо. Просто хочу добавить комментарий для ссылки на представление битов для Integer.MAX_VALUE, Integer.MIN_VALUE, -1, 0, 1 . например System.out.println(Integer.MAX_VALUE + ": " + String.format("%32s", Integer.toBinaryString(Integer.MAX_VALUE)).replace(' ', '0')):; Integer.MAX_VALUE : 01111111111111111111111111111111; Integer.MIN_VALUE : 10000000000000000000000000000000; -1 : 11111111111111111111111111111111; 0 : 00000000000000000000000000000000; 1 : 00000000000000000000000000000001
Энди Донг
6

Логический оператор сдвига вправо ( >>> N) сдвигает биты вправо на N позиций, отбрасывая знаковый бит и дополняя N крайних левых битов нулями. Например:

-1 (in 32-bit): 11111111111111111111111111111111

после >>> 1операции становится:

2147483647: 01111111111111111111111111111111

Арифметический оператор правого сдвига ( >> N) также сдвигает биты вправо на N позиций, но сохраняет знаковый бит и дополняет N крайних левых бит 1. Например:

-2 (in 32-bit): 11111111111111111111111111111110

после >> 1операции становится:

-1: 11111111111111111111111111111111
bigT
источник