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

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.

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?

1 curtida

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

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

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.

1 curtida

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

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

[quote=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.[/quote]

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

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

[quote]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
[/quote]

seria o inverso nos sinais
abrs

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?

[quote]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) [/quote]

Obrigado!

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!

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?

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:

[quote=“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.[/quote]

É 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.

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

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.

[quote=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.[/quote]

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