При арифметическом сдвиге знаковый бит расширяется, чтобы сохранить подпись числа.
Например: -2, представленный в 8 битах, будет 11111110(потому что старший значащий бит имеет отрицательный вес). Сдвиг вправо на один бит с использованием арифметического сдвига даст вам 11111111или -1. Логическое смещение вправо, однако, не заботится о том, чтобы значение могло представлять число со знаком; он просто перемещает все вправо и заполняет слева нулями. Сдвиг нашего -2 правильного бита с использованием логического сдвига даст 01111111.
Хотя я согласен и ценю, что арифметические сдвиги могут быть использованы для умножения чисел со знаком на 2^k, я нахожу странным, что это ответ каждого. Строка битов не является числом и >>всегда может использоваться с любой строкой битов: она всегда выполняет одно и то же, независимо от роли, которую играет строка битов, и независимо от того, имеет ли она понятие «знак». Было бы хорошо дополнить ваш и без того отличный ответ обсуждением случая, когда ваш операнд не интерпретируется как число со знаком? Имеет ли смысл моя жалоба?
Зигги
11
Почему вы говорите, что строка битов не является числом? Вы сказали бы, что последовательность десятичных цифр не является числом?
Данбен
4
@danben Обсуждение, является ли оно числом или нет, имеет смысл только в том случае, если вы связываете его с контекстом. Если интернет - это просто электричество, тогда я согласен, что String - это просто число.
bvdb
1
@danben, но на самом деле, я думаю, что Зигги действительно имел в виду (imho), что a Stringтакже может рассматриваться как a char[]. Он не говорит, что это charне число; он просто говорит, что это число без знака . Я думаю, что там он и потерян.
bvdb
5
@ Зигги прав: не каждая строка битов является числом, и не каждая последовательность десятичных цифр является числом. Например: телефонные номера, почтовые индексы (во многих странах) и т. Д. Являются строками десятичных цифр, но не имеет смысла их добавлять, вычитать или умножать, поэтому они не являются на самом деле числами. Это строки десятичных цифр, но их следует рассматривать как строки символов. (Почтовые коды в Канаде и Великобритании содержат буквы и цифры.)
jcsahnwaldt говорит GoFundMonica
102
>>>беззнаковая смена; это вставит 0. >>подписано, и расширит бит знака.
Операторы сдвига включают сдвиг влево, сдвиг <<вправо со знаком >>и сдвиг вправо без знака >>>.
Значение 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.
Я полагаю, что >>>это без знака, но почему 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=0001111110000000>>>2=00100000
Если мы интерпретируем биты как неотрицательное целое число без знака, логический сдвиг вправо приводит к делению числа на соответствующую степень, равную 2. Однако, если число находится в представлении с двумя дополнительными числами, логическое смещение вправо неправильно делит отрицательные числа. , Например, второй правый сдвиг выше сдвигает от 128 до 32, когда биты интерпретируются как числа без знака. Но он сдвигается от -128 до 32, когда, как это обычно бывает в Java, биты интерпретируются как дополнение к двум.
Следовательно, если вы сдвигаетесь, чтобы делить на степень два, вам нужен арифметический сдвиг вправо ( v >> n). Он возвращает значение, в котором биты vсмещены вправо на nбитовые позиции, а копии самого левого бита v смещены с левой стороны:
01111111>>2=0001111110000000>>2=11100000
Когда биты представляют собой число в представлении, дополняющем два, арифметическое смещение вправо имеет эффект деления на степень два. Это работает, потому что самый левый бит является знаковым битом. Деление на степень два должно держать знак одинаковым.
Битовая комбинация задается левым операндом, а число позиций для смещения - правым операндом. Оператор смещения вправо без знака >>>сдвигает ноль в крайнее левое положение ,
в то время как крайнее левое положение после >>зависит от расширения знака.
Простыми словами >>>всегда смещает ноль в крайнее левое положение, тогда как >>смещения основаны на знаке числа, то есть 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));
Спасибо. Просто хочу добавить комментарий для ссылки на представление битов для 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, представленный в 8 битах, будет
11111110
(потому что старший значащий бит имеет отрицательный вес). Сдвиг вправо на один бит с использованием арифметического сдвига даст вам11111111
или -1. Логическое смещение вправо, однако, не заботится о том, чтобы значение могло представлять число со знаком; он просто перемещает все вправо и заполняет слева нулями. Сдвиг нашего -2 правильного бита с использованием логического сдвига даст01111111
.источник
2^k
, я нахожу странным, что это ответ каждого. Строка битов не является числом и>>
всегда может использоваться с любой строкой битов: она всегда выполняет одно и то же, независимо от роли, которую играет строка битов, и независимо от того, имеет ли она понятие «знак». Было бы хорошо дополнить ваш и без того отличный ответ обсуждением случая, когда ваш операнд не интерпретируется как число со знаком? Имеет ли смысл моя жалоба?String
также может рассматриваться как achar[]
. Он не говорит, что этоchar
не число; он просто говорит, что это число без знака . Я думаю, что там он и потерян.>>>
беззнаковая смена; это вставит 0.>>
подписано, и расширит бит знака.JLS 15.19 Операторы сдвига
Чтобы сделать вещи более понятными, добавив положительный аналог
Поскольку это положительные сдвиги как со знаком, так и со знаком без знака, к левому биту будет добавлено 0.
Смежные вопросы
1 >>> 32 == 1
источник
Они оба сдвига вправо, но
>>>
этоunsigned
Из документации :
источник
>>>
это без знака, но почему7>>32=7
? Я запустил цикл, который делал по одной смене за раз, и увидел, что после32
смен он вернулся7
. Единственный способ, которым это может иметь смысл, состоит в том, что для каждого смещенного числа оно входит во «внешний круг». После32
смены он каким-то образом вернулся к своей позиции, но, очевидно, это все еще не имеет смысла. Что здесь происходит?for (int i = 7 << 1, j = 0; j < 32; j++) System.out.println(Integer.toString(i >>= 1, 2));
) Если вы имеете в виду, почему>>32
сам возвращает исходное значение, посмотрите это .Логическое правое смещение (
v >>> n
) возвращает значение, в котором битыv
сдвинуты вправо наn
битовые позиции, а 0 сдвинуты с левой стороны. Рассмотрим смещение 8-битных значений, записанных в двоичном виде:Если мы интерпретируем биты как неотрицательное целое число без знака, логический сдвиг вправо приводит к делению числа на соответствующую степень, равную 2. Однако, если число находится в представлении с двумя дополнительными числами, логическое смещение вправо неправильно делит отрицательные числа. , Например, второй правый сдвиг выше сдвигает от 128 до 32, когда биты интерпретируются как числа без знака. Но он сдвигается от -128 до 32, когда, как это обычно бывает в Java, биты интерпретируются как дополнение к двум.
Следовательно, если вы сдвигаетесь, чтобы делить на степень два, вам нужен арифметический сдвиг вправо (
v >> n
). Он возвращает значение, в котором битыv
смещены вправо наn
битовые позиции, а копии самого левого бита v смещены с левой стороны:Когда биты представляют собой число в представлении, дополняющем два, арифметическое смещение вправо имеет эффект деления на степень два. Это работает, потому что самый левый бит является знаковым битом. Деление на степень два должно держать знак одинаковым.
источник
>>>
всегда будет ставить 0 в крайнем левом бите, а>>
1 или 0 - в зависимости от того, что это за знак.источник
Узнайте больше о побитовых и битовых операторах
Битовая комбинация задается левым операндом, а число позиций для смещения - правым операндом. Оператор смещения вправо без знака
>>>
сдвигает ноль в крайнее левое положение ,в то время как крайнее левое положение после
>>
зависит от расширения знака.Простыми словами
>>>
всегда смещает ноль в крайнее левое положение, тогда как>>
смещения основаны на знаке числа, то есть 1 для отрицательного числа и 0 для положительного числа.Например, попробуйте как с отрицательными, так и с положительными числами.
вывод:
источник
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
Логический оператор сдвига вправо (
>>> N
) сдвигает биты вправо на N позиций, отбрасывая знаковый бит и дополняя N крайних левых битов нулями. Например:после
>>> 1
операции становится:Арифметический оператор правого сдвига (
>> N
) также сдвигает биты вправо на N позиций, но сохраняет знаковый бит и дополняет N крайних левых бит 1. Например:после
>> 1
операции становится:источник