Різниця між >>> і >>


Відповіді:


408

>>- це арифметичний зсув праворуч, >>>логічний зсув праворуч.

У арифметичному зсуві бітовий знак розширюється для збереження підписаності числа.

Наприклад: -2, представлені у 8 бітах, було б 11111110(оскільки найзначніший біт має негативну вагу). Переміщення його правою біткою за допомогою арифметичного зсуву дасть вам 11111111або -1. Однак, логічний зсув праворуч не хвилює, що значення може представляти підписане число; він просто переміщує все праворуч і заповнює зліва на 0. Зміщення нашого -2 правого біта за допомогою логічного зсуву дасть би 01111111.


8
Хоча я погоджуюся і ціную, що арифметичні зрушення можна використовувати для множення підписаних чисел на 2^k, я вважаю дивним, що це відповідь кожного. Рядок бітів не є числом і >>завжди може бути використаний для будь-якого рядка бітів: він завжди виконує те саме, незалежно від ролі, яку грає рядок бітів, і незалежно від того, чи має вона поняття "знак". Чи було б добре поширити свою вже чудову відповідь обговоренням випадку, коли ваш операнд не трактується як підписаний номер? Чи має сенс моя скарга?
Ziggy

11
Чому ви кажете, що рядок бітів - це не число? Ви б сказали, що послідовність десяткових цифр - це не число?
danben

4
@danben Обговорювати, чи є це чи не число, має сенс лише якщо ви пов'язуєте його з контекстом. Якщо Інтернет - це лише електрика, я згоден, що String - це лише число.
bvdb

1
@danben, але насправді, я думаю, що Ziggy дійсно подумав (imho), що це Stringможе також розглядатися як a char[]. Він не каже, що а char- це не число; він просто каже, що це непідписаний номер. Я думаю, саме там він загубився.
bvdb

5
@ Ziggy має рацію: не кожен рядок бітів - це число, і не кожна послідовність десяткових цифр - це число. Наприклад: Номери телефонів, поштові індекси (у багатьох країнах) тощо - це рядки десяткових цифр, але їх не потрібно додавати, віднімати чи примножувати, тому вони насправді не є цифрами. Вони бувають рядками десяткових цифр, але їх слід розглядати як рядки символів. (Поштові індекси в Канаді та Великобританії містять літери та цифри.)
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 до лівого самого біта.

Пов'язані питання


Без ваших прикладів я б не зрозумів.
mr5

47

Вони обидва зсуву вправо, але >>>єunsigned

З документації :

Оператор непідписаного правого зсуву ">>>" зміщує нуль у крайнє ліве положення, тоді як крайнє ліве положення після ">>" залежить від розширення знака.


12
Ви можете пояснити на прикладі
Kasun Siyambalapitiya

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

Коли біти є числом у поданні доповнення двох, арифметичний правий зсув має ефект ділення на потужність двох. Це працює, тому що крайній лівий біт є бітовим знаком. Ділення на потужність двох повинно зберігати знак однаковим.


38

>>>завжди буде ставити 0 у лівій частині біта, тоді як >>ставитиме 1 або 0 залежно від того, який знак є.


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

Дякую. Просто потрібно додати коментар, щоб посилатися на бітове представлення для 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 більшості лівих бітів 0. Наприклад:

-1 (in 32-bit): 11111111111111111111111111111111

після >>> 1операції стає:

2147483647: 01111111111111111111111111111111

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

-2 (in 32-bit): 11111111111111111111111111111110

після >> 1операції стає:

-1: 11111111111111111111111111111111
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.