Różnica między >>> a >>

Odpowiedzi:

408

>>jest przesunięciem arytmetycznym w prawo, >>>jest przesunięciem logicznym w prawo.

W przesunięciu arytmetycznym bit znaku jest przedłużany w celu zachowania podpisu liczby.

Na przykład: -2 przedstawione w 8 bitach byłoby 11111110(ponieważ najbardziej znaczący bit ma wagę ujemną). Przesunięcie go o jeden bit za pomocą przesunięcia arytmetycznego dałoby ci 11111111, lub -1. Logiczne przesunięcie w prawo nie ma jednak znaczenia, że ​​wartość może reprezentować liczbę ze znakiem; po prostu przesuwa wszystko w prawo i wypełnia od lewej zerami. Przesunięcie naszego -2 o jeden bit za pomocą logicznego przesunięcia dałoby 01111111.

Danben
źródło
8
Chociaż zgadzam się i doceniam, że do arytmetycznego przesuwania można używać mnożenia podpisanych liczb 2^k, wydaje mi się dziwne, że to odpowiedź wszystkich. Łańcuch bitów nie jest liczbą i >>zawsze można go użyć na dowolnym łańcuchu bitów: zawsze robi to samo bez względu na rolę, jaką odgrywa łańcuch bitów i niezależnie od tego, czy ma pojęcie „znaku”. Czy byłoby dobrze, gdybyś udzielił już i tak doskonałej odpowiedzi, omawiając sprawę, gdy twój operand nie jest interpretowany jako liczba podpisana? Czy moja skarga ma sens?
Ziggy
11
Dlaczego mówisz, że ciąg bitów nie jest liczbą? Czy powiedziałbyś, że ciąg cyfr dziesiętnych nie jest liczbą?
danben,
4
@danben Omawianie, czy jest to liczba, czy nie, ma sens tylko wtedy, gdy podłączysz ją do kontekstu. Jeśli internet to tylko elektryczność, to zgadzam się, że String to tylko liczba.
bvdb,
1
@danben, ale myślę, że tak naprawdę Ziggy miał na myśli (imho), że a Stringmożna również uznać za char[]. Nie mówi, że a charnie jest liczbą; on tylko mówi, że jest to liczba bez znaku . Myślę, że tam zginął.
bvdb,
5
@ Ziggy ma rację: nie każdy ciąg bitów jest liczbą i nie każda sekwencja cyfr dziesiętnych jest liczbą. Na przykład: Numery telefonów, kody pocztowe (w wielu krajach) itp. Są ciągami cyfr dziesiętnych, ale ich dodawanie, odejmowanie lub mnożenie nie ma sensu, więc nie są to liczby. Są to ciągi cyfr dziesiętnych, ale należy je traktować jako ciągi znaków. (Kody pocztowe w Kanadzie i Wielkiej Brytanii zawierają litery i cyfry.)
jcsahnwaldt mówi GoFundMonica
102

>>>Przesunięcie jest niepodpisane; wstawi 0. >>jest podpisany i rozszerzy bit znaku.

JLS 15.19 Operatorzy zmiany biegów

Operatory zmiany obejmują przesunięcie w lewo, przesunięcie w <<prawo ze znakiem >>i przesunięcie w prawo bez znaku >>>.

Wartość n>>sto nprzesunięte w prawo spozycje bitów z przedłużeniem znaku .

Wartość n>>>sto nprzesunięte w prawo spozycje bitów z rozszerzeniem zera .

    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"

Aby wyjaśnić, dodając pozytywny odpowiednik

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"

Ponieważ jest to pozytywne, zarówno podpisane, jak i niepodpisane przesunięcia dodadzą 0 do lewego końca.

Powiązane pytania

środki smarujące wielotlenowe
źródło
Bez twoich przykładów nie zrozumiałbym tego.
mr5
47

Oba są przesunięte w prawo, ale tak >>>jestunsigned

Z dokumentacji :

Niepodpisany operator przesunięcia w prawo „>>>” przesuwa zero w skrajne lewe położenie, natomiast skrajne lewe położenie po „>>” zależy od rozszerzenia znaku.

Matt
źródło
12
czy możesz wyjaśnić za pomocą przykładu
Kasun Siyambalapitiya,
1
Myślę też, że powinieneś dać przykład.
byxor
Przypuszczam, że >>>to niepodpisane, ale dlaczego 7>>32=7? Przebiegłem pętlę, która zmieniała się jedna po drugiej i zobaczyłem, że po 32zmianie wrócił do 7. Jedynym sposobem, który może to mieć sens, jest to, że dla każdej przesuniętej liczby wchodziła ona w „zewnętrzny krąg”. Po 32zmianach w jakiś sposób wrócił do swojej pozycji, ale oczywiście to nadal nie ma sensu. Co się dzieje?
Ian Limarta
@IanLimarta To nie? Właśnie dostaję 0. ( for (int i = 7 << 1, j = 0; j < 32; j++) System.out.println(Integer.toString(i >>= 1, 2));) Jeśli masz na myśli, dlaczego >>32sama zwraca pierwotną wartość, zobacz to .
Moira
Przepraszam. Miałem na myśli, dlaczego „7 >>> 32 = 7”.
Ian Limarta,
40

Logiczne przesunięcie w prawo ( v >>> n) zwraca wartość, w której bity vzostały przesunięte w prawo o npozycje bitów, a cyfry 0 są przesunięte z lewej strony. Rozważ przesunięcie wartości 8-bitowych zapisanych w systemie binarnym:

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

Jeśli interpretujemy bity jako niepodpisaną nieujemną liczbę całkowitą, logiczne przesunięcie w prawo powoduje podzielenie liczby przez odpowiadającą jej potęgę 2. Jeśli jednak liczba jest reprezentowana przez uzupełnienie dwóch, logiczne przesunięcie w prawo nie dzieli poprawnie liczb ujemnych . Na przykład drugie przesunięcie w prawo powyżej przesuwa 128 do 32, gdy bity są interpretowane jako liczby bez znaku. Ale przesuwa się z -128 na 32, gdy, jak to jest typowe w Javie, bity są interpretowane jako uzupełnienie dwóch.

Dlatego jeśli przesuwasz się, aby podzielić przez potęgę dwóch, potrzebujesz arytmetycznego przesunięcia w prawo ( v >> n). Zwraca wartość, w której bity vzostały przesunięte w prawo o npozycje bitów, a kopie najbardziej lewego bitu v są przesunięte z lewej strony:

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

Kiedy bity są liczbą w reprezentacji dwóch uzupełnień, arytmetyczne przesunięcie w prawo powoduje dzielenie przez potęgę dwóch. Działa to, ponieważ skrajnie lewy bit jest bitem znaku. Dzielenie przez potęgę dwóch musi zachować znak bez zmian.

andru
źródło
38

>>>zawsze umieści 0 w lewym bicie, a >>1 lub 0 w zależności od tego, jaki jest jego znak.

corsiKa
źródło
10

Przeczytaj więcej o operatorach Bitwise i Bit Shift

>>      Signed right shift
>>>     Unsigned right shift

Wzór bitowy jest podawany przez lewy operand, a liczba pozycji do przesunięcia przez prawy operand. Niepodpisany prawy operator >>> zmiany biegów przesuwa zero na skrajne lewe położenie ,

podczas gdy pozycja najbardziej po lewej >>zależy od rozszerzenia znaku.

W prostych słowach >>>zawsze przesuwa zero do skrajnej lewej pozycji, podczas gdy >>przesuwa się na podstawie znaku liczby, tj. 1 dla liczby ujemnej i 0 dla liczby dodatniej.


Na przykład spróbuj z liczbami ujemnymi i dodatnimi.

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));

wynik:

11111111111111111111111111011001
11111111111111111111111101100100
  111111111111111111111111011001
11111111111111111111111101100100

                          100110
                        10011000
                          100110
                        10011000
Braj
źródło
Dzięki. Chcę tylko dodać komentarz odnoszący się do reprezentacji bitów dla Integer.MAX_VALUE, Integer.MIN_VALUE, -1, 0, 1 . na przykład: 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
Andy Dong
6

Operator logiczny przesunięcia w prawo ( >>> N) przesuwa bity w prawo o N pozycji, odrzucając bit znaku i dopełniając N bitów najbardziej w lewo zerami. Na przykład:

-1 (in 32-bit): 11111111111111111111111111111111

po >>> 1operacji staje się:

2147483647: 01111111111111111111111111111111

Operator arytmetyczny z przesunięciem w prawo ( >> N) również przesuwa bity w prawo o N pozycji, ale zachowuje bit znaku i wypełnia N bitów najbardziej w lewo za pomocą 1. Na przykład:

-2 (in 32-bit): 11111111111111111111111111111110

po >> 1operacji staje się:

-1: 11111111111111111111111111111111
bigT
źródło