Diferença entre >>> e >>

Respostas:

408

>> é a mudança aritmética certa, >>> é a mudança lógica certa.

Em um deslocamento aritmético, o bit de sinal é estendido para preservar a assinatura do número.

Por exemplo: -2 representado em 8 bits seria 11111110(porque o bit mais significativo tem peso negativo). Mudar um pouco para a direita usando a mudança aritmética daria a você 11111111, ou -1. O deslocamento lógico para a direita, no entanto, não se importa que o valor possa representar um número assinado; simplesmente move tudo para a direita e preenche da esquerda com 0s. Mudar nosso -2 para a direita usando um deslocamento lógico daria 01111111.

danben
fonte
8
Embora eu concorde e aprecie que as mudanças aritméticas possam ser usadas para multiplicar números assinados 2^k, acho estranho que essa seja a resposta de todos. Uma cadeia de bits não é um número e >>sempre pode ser usada em qualquer cadeia de bits: sempre faz a mesma coisa, independentemente do papel que a cadeia de bits está desempenhando e independentemente do conceito de 'sinal'. Seria bom estender sua já ótima resposta com uma discussão do caso em que seu operando não está sendo interpretado como um número assinado? A minha reclamação faz sentido?
Ziggy
11
Por que você diz que uma sequência de bits não é um número? Você diria que uma sequência de dígitos decimais não é um número?
Danben
4
@danben Discutir se é ou não um número, só faz sentido se você o vincular a um contexto. Se a internet é apenas eletricidade, concordo que uma String é apenas um número.
Bvdb 17/08/2015
11
@danben mas, na verdade, acho que o que Ziggy estava realmente se referindo (imho), é que um Stringtambém pode ser considerado um char[]. Ele não está dizendo que a charnão é um número; ele está apenas dizendo que é um número não assinado . Eu acho que é onde ele está perdido.
bvdb
5
@Ziggy está certo: nem toda sequência de bits é um número e nem toda sequência de dígitos decimais é um número. Por exemplo: números de telefone, códigos postais (em muitos países) etc. são cadeias de dígitos decimais, mas não faz sentido adicioná-las, subtraí-las ou multiplicá-las, para que não sejam realmente números. Por acaso são sequências de dígitos decimais, mas devem ser tratadas como sequências de caracteres. (Os códigos postais no Canadá e no Reino Unido contêm letras e dígitos.)
jcsahnwaldt disse GoFundMonica
102

>>>é turno não assinado; ele irá inserir 0.>> está assinado e estenderá o bit de sinal.

Operadores de turno JLS 15.19

Os operadores de turno incluem turno esquerdo <<, turno direito assinado >>e turno direito não assinado>>> .

O valor de n>>sé posições de bits ndeslocadas à direita scom extensão de sinal .

O valor de n>>>sé posições de bits ndeslocadas à direita scom extensão zero .

    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"

Para tornar as coisas mais claras, adicionando contrapartida positiva

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"

Como é positivo, os turnos assinados e não assinados adicionarão 0 à esquerda, na maioria dos bits.

Perguntas relacionadas

poligenelubricants
fonte
Sem seus exemplos, eu não entenderia.
MR5
47

Ambos estão no turno certo, mas >>>éunsigned

A partir da documentação :

O operador de mudança à direita não assinado ">>>" muda um zero para a posição mais à esquerda, enquanto a posição mais à esquerda após ">>" depende da extensão do sinal.

Matt
fonte
12
você pode explicar com um exemplo
Kasun Siyambalapitiya 4/16/16
11
Eu também acho que você deveria dar um exemplo.
By decor
Suponho que >>>não esteja assinado, mas por que 7>>32=7? Corri um loop que fazia um turno de cada vez e vi que, depois dos 32turnos, ele voltava a 7. A única maneira de fazer sentido é que, para cada número alterado, ele entra em um "círculo externo". Após os 32turnos, voltou de alguma forma à sua posição, mas obviamente isso ainda não faz sentido. O que está acontecendo?
Ian Limarta
@IanLimarta Não faz? Acabei de receber 0. ( for (int i = 7 << 1, j = 0; j < 32; j++) System.out.println(Integer.toString(i >>= 1, 2));) Se você quer dizer por que >>32ele retorna o valor original, veja isso .
Moira
Eu sinto Muito. Eu quis dizer por que '7 >>> 32 = 7'.
Ian Limarta 31/03
40

O deslocamento lógico para a direita ( v >>> n) retorna um valor no qual os bits vforam deslocados para a direita pelas nposições dos bits e os 0 são deslocados do lado esquerdo. Considere mudar os valores de 8 bits, escritos em binário:

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

Se interpretarmos os bits como um número inteiro não negativo não assinado, o deslocamento lógico para a direita terá o efeito de dividir o número pela potência correspondente de 2. No entanto, se o número estiver na representação de complemento de dois, o deslocamento lógico à direita não dividirá corretamente os números negativos. . Por exemplo, o segundo deslocamento à direita acima muda de 128 para 32 quando os bits são interpretados como números não assinados. Mas muda de -128 para 32 quando, como é típico em Java, os bits são interpretados no complemento de dois.

Portanto, se você estiver mudando para dividir por uma potência de dois, deseja o deslocamento aritmético para a direita ( v >> n). Ele retorna um valor no qual os bits vforam deslocados para a direita porn posições dos bits e as cópias do bit mais à esquerda de v são deslocadas do lado esquerdo:

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

Quando os bits são um número na representação do complemento de dois, o deslocamento aritmético para a direita tem o efeito de dividir por uma potência de dois. Isso funciona porque o bit mais à esquerda é o bit de sinal. Dividir por um poder de dois deve manter o sinal igual.

andru
fonte
38

>>>sempre colocará 0 no bit mais à esquerda, enquanto >>colocará 1 ou 0, dependendo de qual seja o sinal.

corsiKa
fonte
10

Leia mais sobre os operadores Bitwise e Bit Shift

>>      Signed right shift
>>>     Unsigned right shift

O padrão de bits é dado pelo operando do lado esquerdo e o número de posições a serem deslocadas pelo operando do lado direito. O operador de mudança à direita não assinado >>> muda o zero para a posição mais à esquerda ,

enquanto a posição mais à esquerda após >> depende da extensão do sinal.

Em palavras simples, >>>sempre desloca um zero para a posição mais à esquerda, enquanto >>desloca com base no sinal do número, ou seja, 1 para número negativo e 0 para número positivo.


Por exemplo, tente com números negativos e positivos.

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

resultado:

11111111111111111111111111011001
11111111111111111111111101100100
  111111111111111111111111011001
11111111111111111111111101100100

                          100110
                        10011000
                          100110
                        10011000
Braj
fonte
Obrigado. Só quero adicionar um comentário para referenciar a representação de bits para Integer.MAX_VALUE, Integer.MIN_VALUE, -1, 0, 1 . por exemplo 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

O operador lógico de deslocamento à direita ( >>> N) desloca os bits para a direita pelas posições N, descartando o bit de sinal e preenchendo os N bits mais à esquerda com zeros. Por exemplo:

-1 (in 32-bit): 11111111111111111111111111111111

depois que uma >>> 1operação se tornar:

2147483647: 01111111111111111111111111111111

O operador aritmético de deslocamento à direita ( >> N) também desloca os bits para a direita pelas posições N, mas preserva o bit de sinal e preenche os N bits mais à esquerda com 1's. Por exemplo:

-2 (in 32-bit): 11111111111111111111111111111110

depois que uma >> 1operação se tornar:

-1: 11111111111111111111111111111111
bigT
fonte