Os operadores de troca de bits fazem exatamente o que o nome indica. Eles trocam bits. Aqui está uma breve introdução (ou não tão breve) aos diferentes operadores de turno.
Os operadores
>>
é o operador aritmético (ou assinado) do deslocamento à direita.
>>>
é o operador de mudança à direita lógico (ou não assinado).
<<
é o operador de turno esquerdo e atende às necessidades de turnos lógicos e aritméticos.
Todos estes operadores pode ser aplicada aos valores inteiros ( int
, long
, possivelmente, short
e byte
ou char
). Em alguns idiomas, a aplicação dos operadores shift a qualquer tipo de dados menor que int
redimensiona automaticamente o operando para ser um int
.
Observe que <<<
não é um operador, porque seria redundante.
Observe também que C e C ++ não fazem distinção entre os operadores de turno certo . Eles fornecem apenas o >>
operador, e o comportamento de mudança à direita é a implementação definida para tipos assinados. O restante da resposta usa os operadores C # / Java.
(Em todas as implementações C e C ++ convencionais, incluindo GCC e Clang / LLVM, os >>
tipos assinados são aritméticos. Alguns códigos assumem isso, mas não é algo que o padrão garante. Porém, não é indefinido ; o padrão exige implementações para defini-lo como um No entanto, as mudanças à esquerda de números com sinal negativo não são um comportamento indefinido (estouro de número inteiro assinado). Portanto, a menos que você precise de uma mudança aritmética à direita, geralmente é uma boa ideia fazer a troca de bits com tipos não assinados.)
Deslocamento para a esquerda (<<)
Os números inteiros são armazenados, na memória, como uma série de bits. Por exemplo, o número 6 armazenado como um de 32 bits int
seria:
00000000 00000000 00000000 00000110
Mudar esse padrão de bit para a posição esquerda ( 6 << 1
) resultaria no número 12:
00000000 00000000 00000000 00001100
Como você pode ver, os dígitos foram deslocados para a esquerda em uma posição e o último dígito à direita é preenchido com um zero. Você também pode observar que o deslocamento para a esquerda é equivalente à multiplicação por potências de 2. Portanto, 6 << 1
é equivalente a 6 * 2
e 6 << 3
é equivalente a 6 * 8
. Um bom compilador de otimização substituirá multiplicações por turnos quando possível.
Mudança não circular
Observe que estes não são turnos circulares. Deslocando esse valor para a esquerda em uma posição ( 3,758,096,384 << 1
):
11100000 00000000 00000000 00000000
resulta em 3.221.225.472:
11000000 00000000 00000000 00000000
O dígito que é deslocado "no final" é perdido. Não envolve.
Deslocamento lógico para a direita (>>>)
Um deslocamento lógico para a direita é o inverso para o deslocamento para a esquerda. Em vez de mover bits para a esquerda, eles simplesmente se movem para a direita. Por exemplo, mudando o número 12:
00000000 00000000 00000000 00001100
à direita em uma posição ( 12 >>> 1
) retornará nosso 6 original:
00000000 00000000 00000000 00000110
Portanto, vemos que mudar para a direita é equivalente à divisão por potências de 2.
Pedaços perdidos se foram
No entanto, uma mudança não pode recuperar bits "perdidos". Por exemplo, se mudarmos esse padrão:
00111000 00000000 00000000 00000110
para a esquerda 4 posições ( 939,524,102 << 4
), temos 2.147.483.744:
10000000 00000000 00000000 01100000
e, em seguida, mudando de volta ( (939,524,102 << 4) >>> 4
), obtemos 134.217.734:
00001000 00000000 00000000 00000110
Não podemos recuperar nosso valor original depois que perdemos os bits.
Desvio aritmético para a direita (>>)
O deslocamento aritmético para a direita é exatamente igual ao deslocamento lógico para a direita, exceto que, em vez de preencher com zero, ele almofada com o bit mais significativo. Isso ocorre porque o bit mais significativo é o bit de sinal ou o bit que distingue números positivos e negativos. Ao preencher com o bit mais significativo, a mudança aritmética para a direita preserva os sinais.
Por exemplo, se interpretarmos esse padrão de bits como um número negativo:
10000000 00000000 00000000 01100000
nós temos o número -2.147.483.552. Mudar isso para as 4 posições corretas com o deslocamento aritmético (-2.147.483.552 >> 4) nos daria:
11111000 00000000 00000000 00000110
ou o número -134.217.722.
Portanto, vemos que preservamos o sinal de nossos números negativos, usando o deslocamento aritmético para a direita, em vez do deslocamento lógico para a direita. E mais uma vez, vemos que estamos realizando a divisão por potências de 2.