O que são operadores de turno bitwise (bit-shift) e como eles funcionam?

I'tenho tentado aprender C no meu tempo livre, e outras linguagens (C#, Java, etc.) têm o mesmo conceito (e muitas vezes os mesmos operadores) ...

O que eu'estou me perguntando é, a um nível central, o que faz o bit-shifting (<<, >>, >>>>), que problemas ele pode ajudar a resolver, e o que gotchas espreitam na curva? Em outras palavras, um guia absoluto para principiantes's para a mudança de bits em toda a sua bondade.

Solução

Os operadores de mudança de bits fazem exactamente o que o seu nome implica. Eles mudam os bits. Aqui está uma breve (ou não-tão-briefe) introdução aos diferentes operadores de mudança de bit.

Os Operadores

  • >> é o operador de turno direito aritmético (ou assinado).
  • >>> é o operador lógico (ou não assinado) do turno da direita.
  • ``)

O deslocamento aritmético direito é exatamente como o deslocamento lógico direito, exceto que ao invés de estofar com zero, ele estoca com o bit mais significativo. Isto porque o bit mais significativo é o bit sign, ou o bit que distingue números positivos e negativos. Ao almofadar com o bit mais significativo, o deslocamento aritmético para a direita é o sinal-preservante.

Por exemplo, se interpretarmos este padrão de bits como um número negativo:

10000000 00000000 00000000 01100000

temos o número -2.147.483.552. Mudando isso para a direita 4 posições com o deslocamento aritmético (-2.147.483.552 >> 4) nos daria:

11111000 00000000 00000000 00000110

ou o número -134.217.722.

Assim, vemos que preservamos o sinal de nossos números negativos usando o deslocamento aritmético direito, ao invés do deslocamento lógico direito. E mais uma vez, vemos que estamos a fazer a divisão por poderes de 2.

Comentários (22)

Digamos que temos um único byte:

0110110

Aplicar um único bitshift para a esquerda nos leva:

1101100

O zero mais esquerdo foi deslocado para fora do byte, e um novo zero foi anexado à extremidade direita do byte.

Os pedaços não rolam; eles são descartados. Isso significa que se você sair do turno 1101100 e depois do turno da direita, você não terá o mesmo resultado de volta.

O deslocamento à esquerda por N é equivalente a multiplicar por 2N.

Mudar para a direita por N é (se você estiver usando [um complemento][1]) é o equivalente a dividir por 2N e arredondar para zero.

O bitshifting pode ser usado para multiplicação e divisão insanamente rápidas, desde que você esteja trabalhando com um poder de 2. Quase todas as rotinas gráficas de baixo nível usam o bitshifting.

Por exemplo, antigamente, utilizávamos o modo 13h (320x200 256 cores) para os jogos. No modo 13h, a memória de vídeo era disposta sequencialmente por pixel. Isso significava que para calcular a localização de um pixel, você usaria a seguinte matemática:

memoryOffset = (row * 320) + column

Agora, naquele tempo, a velocidade era crítica, por isso usávamos os bitshifts para fazer esta operação.

No entanto, 320 não é um poder de dois, por isso para contornar isso temos de descobrir o que é um poder de dois que somados juntos faz 320:

(row * 320) = (row * 256) + (row * 64)

Agora podemos converter isso em turnos de esquerda:


(row * 320) = (row 
Comentários (6)

O que se entende é que o seguinte é dependente da implementação (de acordo com a norma ANSI):

char x = -1;
x >> 1;

x pode agora ser 127 (01111111) ou ainda -1 (1111111111).

Na prática, normalmente é a última.

Comentários (3)