Відповіді:
>>
- це арифметичний зсув праворуч, >>>
логічний зсув праворуч.
У арифметичному зсуві бітовий знак розширюється для збереження підписаності числа.
Наприклад: -2, представлені у 8 бітах, було б 11111110
(оскільки найзначніший біт має негативну вагу). Переміщення його правою біткою за допомогою арифметичного зсуву дасть вам 11111111
або -1. Однак, логічний зсув праворуч не хвилює, що значення може представляти підписане число; він просто переміщує все праворуч і заповнює зліва на 0. Зміщення нашого -2 правого біта за допомогою логічного зсуву дасть би 01111111
.
2^k
, я вважаю дивним, що це відповідь кожного. Рядок бітів не є числом і >>
завжди може бути використаний для будь-якого рядка бітів: він завжди виконує те саме, незалежно від ролі, яку грає рядок бітів, і незалежно від того, чи має вона поняття "знак". Чи було б добре поширити свою вже чудову відповідь обговоренням випадку, коли ваш операнд не трактується як підписаний номер? Чи має сенс моя скарга?
String
може також розглядатися як a char[]
. Він не каже, що а char
- це не число; він просто каже, що це непідписаний номер. Я думаю, саме там він загубився.
>>>
є беззнаковою зміною; він вставить 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 до лівого самого біта.
1 >>> 32 == 1
Вони обидва зсуву вправо, але >>>
єunsigned
З документації :
Оператор непідписаного правого зсуву ">>>" зміщує нуль у крайнє ліве положення, тоді як крайнє ліве положення після ">>" залежить від розширення знака.
>>>
це не підписано, але чому це так 7>>32=7
? Я пробіг цикл, який робив одну зміну за часом, і побачив, що після 32
змін він повернувся до 7
. Єдиний спосіб, що це може мати сенс, це те, що для кожного зміщеного числа воно входило в "зовнішнє коло". Після 32
зрушень вона якось повернулася до своєї позиції, але очевидно, що все ще не має сенсу. Що відбувається?
Логічний правий зсув ( 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
Коли біти є числом у поданні доповнення двох, арифметичний правий зсув має ефект ділення на потужність двох. Це працює, тому що крайній лівий біт є бітовим знаком. Ділення на потужність двох повинно зберігати знак однаковим.
Детальніше про операцій з побітним розрядом та зсувом біт
>> 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
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 більшості лівих бітів 0. Наприклад:
-1 (in 32-bit): 11111111111111111111111111111111
після >>> 1
операції стає:
2147483647: 01111111111111111111111111111111
Арифметичний оператор правого зсуву ( >> N
) також зміщує біти вправо на N позицій, але зберігає біт знаків і прошиває N найбільш білих лівих на 1. Наприклад:
-2 (in 32-bit): 11111111111111111111111111111110
після >> 1
операції стає:
-1: 11111111111111111111111111111111