Operadores bit a bit << >> e >>>

15 respostas
J

Opa… alguem podia dar uma mao ?
Essa parada de bit mais importante antes da mudanca dos bits do operador >> ta me deixando um pouco confuso :slight_smile:
alguem me ajuda ?

Valeu e abracos.

15 Respostas

L

os operadores bit a bit <<, >> e >>> fazer deslocamento

vc conhece notacao binaria de numeros ne?
e representacao de numeros negativos? java usa complemento de 2.

contando que o bit significativo (maior valor) fica a esquerda temos:

13 (1101)

13 << 2 -> 52
1101 -> 110100

o >> é deslocamento logico, preenche sempre com zero a esquerda
o >>> é deslocamento matematico, preenche sempre o sinal a esquerda

13 >> 2 - > 3
13 >>> 2 -> 3
1101 -> 11

ok, mas pro numero negativo -5 o resultado muda, primeiro vamos calcular a representação dele:
5 -> 0101
-5 -> 1010 + 1 -> 1011

1011 (-5) >> 2 -> 0010 (2)
1011 (-5) >>> 2 -> 1110 (-2)

alguma duvida?

J

tipo… o que eu consegui entender ate agora onde eu li e que os operadores << e >>> eles adicionam 0 aos novos bits correto ? e o operador >> ele condiciona o novo bit ao bit mais relevante antes da mudanca. Agora vem a duvida realmente… como eu posso descobrir o bit mais relevante nessa mudanca e outra sera que vc tem mais exemplos pra colocar aqui ? ja me ajudaram bastante.

obrigado

B

Acho que o que está te confundindo é o bit do sinal…
Se o número é positivo, o bit mais da esquerda é 0, e se é negativo, é 1. Isso porque os inteiros em Java são “signed”, ou seja, o bit da esquerda serve simplesmente para representar o sinal.
Dessa forma, se o número for positivo, ao fazer o deslocamento ele vai preencher com 0s a esquerda, e se for negativo, vai preencher com 1s

L

bani, não é exatamente isso, pq java usa complemento de 2, mas sim, sempre que tivermos o bit mais significativo setado, ele é negativo.

Cada tipo inteiro do java possui 1 tamanho em bits fixo:

long -> 64
int -> 32
short -> 16
byte -> 8
(vou omitir o tipo char pra nao complicar as coisas)

ok?
codigo binario funciona feito o decimal, mas so tem digitos 0 e 1
o numero:
1234
nao é a mesma coisa que
1 * 1000 +
2 * 100 +
3 * 10 +
4 * 1
o 1 é o bit mais significativo e o 4 o menos.

a mesma coisa vale pra representacao binaria:

00001001 (9 em decimal)
o 1 a direita é o mais significativo

como funciona conversao entre binario e decimal?
sem entrar no merito da teoria, como regra pratica vc faz assim:
vai da direita pra esquerda somando os numeros das varias casas da seguinte forma:
d * 2 ^ i
onde:
d é o digito na casa em questão
i é a posição do digito no número, conte da direita pra esquerda e comece no zero.
^ é pra exponenciação
entao
00001001 fica:
1 * 2 ^ 0 = 1
0 * 2 ^ 1 = 0 +
0 * 2 ^ 2 = 0 +
1 * 2 ^ 3 = 8 + (=9)

Muito bem, já da pra explicar os operadores de shift.
Esses 3 operadores funcionam deslocando, ‘empurrando’, os bits para a esquerda ou para a direita.

nosso exemplo 1 byte, tem 8 bits lembra?, com o numero 9 fica 00001001
vamos ver oq acontece com os varios shifts:

00001001 << 1 = 00010010
00001001 << 2 = 00100100
00001001 << 3 = 01001000
00001001 << 4 = 10010000
00001001 << 5 = 00100000
00001001 << 6 = 01000000
00001001 << 7 = 10000000
00001001 << 8 = 00000000

00001001 >> 1 = 00000100
00001001 >> 2 = 00000010
00001001 >> 3 = 00000001
00001001 >> 4 = 00000000

00001001 >>> 1 = 00000100
00001001 >>> 2 = 00000010
00001001 >>> 3 = 00000001
00001001 >>> 4 = 00000000

Ate aqui tudo bem? Ok, mas >> e >>> fazem a mesma coisa não? Aparentemente sim, a diferença é sutil, mas fundamental.

Primeiro a explicação do pq, se tiver notado o << vai multiplicando o numero por 2, entao 10 << 1 = 10 * 2 = 20, 10 << 2 = 10 * 2 * 2 = 40
e da mesma forma >> e >>> vao dividindo: 16 >> 1 = 8, 16 >> 3 = 2.

Java pode guardar numeros negativos num byte tambem, porem esse esquema que mostrei agora nao resolve isso, pq so guarda numeros positivos e o zero. É ai que entra a notação de complemento de 2, é a forma com que todas maquinas de hoje em dia usam pra representar numeros negativos, a formula é bem simples:

dado o numero x positivo vc inverte os bits (quem era 0 vira 1 e vice-versa) e depois soma 1, pronto vc tem -x. Ex:

10 = 00001010
invertemos os bits:
11110101
somamos 1
11110110
pronto, -10 em binario é 11110110 (isso quando tamos usando 8 bits, senao vc extende com 1’s a esquerda)

aqui que aparece a diferença entre >> e >>>.
esses operadores vao ‘empurrar’ os bits a direita. Porem como vc pode imaginar, fazer simplemente isso aquela propriedade de ir dividindo o numero por 2 nao vale mais pq:
11110110 (-10) >> 1 =
01111011 não é -5 e sim 123.
Pra isso serve o >>>, ele vai preencher a esquerda com o bit do sinal, ai vai dar a conta que voce esperava:
11110110 >>> 1 =
11111011 = -5

Pra nao ficar nenhuma duvida:

0110 >>> 1 -> 0011
1000 >>> 1 -> 1100

espero ter exclarecido sua duvida.

S

louds explicação mt boa.
Não só tirou a duvida do
JBoy__ como a minha também.
vlw :wink:

R

Ótima a explicação, muito completa e clara.
Tirou todas minhas dúvidas.

R

louds:


nao é a mesma coisa que
1 * 1000 +
2 * 100 +
3 * 10 +
4 * 1
o 1 é o bit mais significativo e o 4 o menos.

a mesma coisa vale pra representacao binaria:

00001001 (9 em decimal)
o 1 a direita é o mais significativo

espero ter exclarecido sua duvida.

louds seria o bit 1 mais a esquerda o mais significativo.

G

Embora o post seja muito antigo, creio q muita gente pode encontrar por ai e tentar se basear nele,… excelente explicacao louds, mas tem um porem… vc acabou trocando, o operador >>> nao considera o sinal e sim o >> que considera, entao aqui

Pra isso serve o >>>, ele vai preencher a esquerda com o bit do sinal, ai vai dar a conta que voce esperava:
11110110 >>> 1 =
11111011 = -5

Pra nao ficar nenhuma duvida:

0110 >>> 1 -> 0011
1000 >>> 1 -> 1100

seria o inverso nos sinais
abrs

D

Boa tarde, estou tentando intender este negócio de modificadores binários, e encontrei este tópico, entendi bem, exceto a parte de somar 1 no valor abaixo, por exemplo, como é feita detalhadamente esta soma de 1 que transformou 11110101 em 11110110?

10 = 00001010
invertemos os bits:
11110101
somamos 1
11110110
pronto, -10 em binario é 11110110 (isso quando tamos usando 8 bits, senao vc extende com 1’s a esquerda)

Obrigado!

G

Boas, blz?

Entao para chegar de 11110101 em 11110110 adicionando 1 é simples.

11110101

  • 1
    

1 + 1 = 0 pendura 1

entao teremos ,
agora adiciona 1 pendurado ao penultimo zero

11110100

  • 1
    

teremos

11110110 = resultado final

Abraço!

R

Bom dia galera, estou com uma dúvida ao colocar os valores 91,6 nos parâmetros do método

public static byte[] intToBytes(int value, int size) {
        byte[] result = new byte[size];
        for (int i=0; i<size; i++) {
            result[i] = (byte) ((value >> (i * 8)) & 0xFF);
        }
        return result;
    }

imprime 91,0,0,0,91,0. Não deveria imprimir 91,0,0,0,0,0? Por que ele tem esse comportamento?

V

O shift trabalha da seguinte forma:

num >> bits

É equivalente a

num >> (bits % totalDeBits)

Portanto, um shift de 32 num inteiro (que tem 32 bits) é equivalente a um shift de 0 (pois 32 % 32 == 0).

Esse comportamento esquisito está descrito na JLS 15.19:

“JSL15.19”:
If the promoted type of the left-hand operand is int, only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.

If the promoted type of the left-hand operand is long, then only the six lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x3f (0b111111). The shift distance actually used is therefore always in the range 0 to 63, inclusive.

É isso que está ocorrendo em seu caso. A variável value é um int, de 32 bits, portanto, só possui 4 bytes. Como você mandou usar 6 bytes, quando i for = 4, ele fará o shift em 0, retornando novamente 91. Por isso o resultado é 91,0,0,91,0.

Para corrigir seu método, o ideal seria fazer assim:

public static byte[] intToBytes(int value, int size) {
        byte[] result = new byte[size];
        for (int i=0; i < size; i++) {
            int v = value & 0xFF;
            result[i] = (byte)v;
            value >>= 8;
        }
        return result;
    }

E, melhor ainda, usar:

result[size-i-1] = (byte)v;

Para o vetor result ficar ordenado do byte mais para o menos significativo.

V

Por que destruiu sua pergunta? Era uma ótima pergunta.

R

Bom dia Vini, não sei por que parte da pergunta sumiu, não lembro de ter feito nada, bom irei colocar de volta a propósito
excelente explicação entendi perfeitamente.

Obrigado.

V

robson.nunes:
Bom dia Vini, não sei por que parte da pergunta sumiu, não lembro de ter feito nada, bom irei colocar de volta a propósito
excelente explicação entendi perfeitamente.

Obrigado.

Eu restaurei o que lembrava da pergunta. Estava totalmente apagada.

Criado 2 de maio de 2003
Ultima resposta 6 de out. de 2014
Respostas 15
Participantes 10