>>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.
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.
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.
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.
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=0001111110000000>>>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=0001111110000000>>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.
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));
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:
Odpowiedzi:
>>
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 ci11111111
, 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łoby01111111
.źródło
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?String
można również uznać zachar[]
. Nie mówi, że achar
nie jest liczbą; on tylko mówi, że jest to liczba bez znaku . Myślę, że tam zginął.>>>
Przesunięcie jest niepodpisane; wstawi 0.>>
jest podpisany i rozszerzy bit znaku.JLS 15.19 Operatorzy zmiany biegów
Aby wyjaśnić, dodając pozytywny odpowiednik
Ponieważ jest to pozytywne, zarówno podpisane, jak i niepodpisane przesunięcia dodadzą 0 do lewego końca.
Powiązane pytania
1 >>> 32 == 1
źródło
Oba są przesunięte w prawo, ale tak
>>>
jestunsigned
Z dokumentacji :
źródło
>>>
to niepodpisane, ale dlaczego7>>32=7
? Przebiegłem pętlę, która zmieniała się jedna po drugiej i zobaczyłem, że po32
zmianie wrócił do7
. 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”. Po32
zmianach w jakiś sposób wrócił do swojej pozycji, ale oczywiście to nadal nie ma sensu. Co się dzieje?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>>32
sama zwraca pierwotną wartość, zobacz to .Logiczne przesunięcie w prawo (
v >>> n
) zwraca wartość, w której bityv
zostały przesunięte w prawo on
pozycje bitów, a cyfry 0 są przesunięte z lewej strony. Rozważ przesunięcie wartości 8-bitowych zapisanych w systemie binarnym: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 bityv
zostały przesunięte w prawo on
pozycje bitów, a kopie najbardziej lewego bitu v są przesunięte z lewej strony: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.
źródło
>>>
zawsze umieści 0 w lewym bicie, a>>
1 lub 0 w zależności od tego, jaki jest jego znak.źródło
Przeczytaj więcej o operatorach Bitwise i Bit 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.
wynik:
źródło
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
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:po
>>> 1
operacji staje się: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:po
>> 1
operacji staje się:źródło