O que acontece nesse algoritmo?

int binToDec(string bin){ int ret = 0; int i = 0; while(bin[i] == '0' || bin[i] == '1'){ if(bin[i] == '0'){ ret <<= 1; }else{ ret ^= 1; ret <<= 1; } i++; } ret >>= 1; return ret; }

Alguém consegue me descrever linha a linha o que ocorre dentro do while ali ?!

Simplesmente não consigo entender (eu entendo que ali estão utilizando bitshift, mas o que acontece nesse bitshift ?).

Você precisa conhecer o sistema binário de números:

Para após isso entender como funciona a troca (shift) dos bits:
http://www.diogomatheus.com.br/blog/php/operadores-bitwise-bit-a-bit/

while(bin[i] == '0' || bin[i] == '1'){ if(bin[i] == '0'){ ret <<= 1; // move em uma posição o bit para a esquerda(ex: 00000001 -> 00000010) }else{ ret ^= 1; // realiza um ou exclusivo com 1(ou seja verdadeiro) ret <<= 1; } i++; // incrementa i em 1 ^_^ }

http://pt.wikibooks.org/wiki/Java/Operadores

Só digo: lOl…

Eu conheco o sistema de numeração (incluindo qualquer base numerica), mas o que eu não consigo compreender é como utilizar esses operadores de bit pra resolução de algum problema, simplesmente não entra na minha cabeça.
Eu ja li varios posts explicando mas nada me faz entender como utiliza-los…

Logica &:
10011
11101


10001

Logica |:
10011
11101


11111

Mas aqueles especiais: ^, >>, << não os entendo…

Será que alguem ai não tem alguma explicação que me faça entender isso, estou realmente necessitando de entender isso.

OBRIGADO !

[quote=Vinicius Zibetti Resko]Só digo: lOl…

Eu conheco o sistema de numeração (incluindo qualquer base numerica), mas o que eu não consigo compreender é como utilizar esses operadores de bit pra resolução de algum problema, simplesmente não entra na minha cabeça.
Eu ja li varios posts explicando mas nada me faz entender como utiliza-los…

Logica &:
10011
11101


10001

Logica |:
10011
11101


11111

Mas aqueles especiais: ^, >>, << não os entendo…

Será que alguem ai não tem alguma explicação que me faça entender isso, estou realmente necessitando de entender isso.

OBRIGADO ![/quote]

Vinícius, isso é uma máscara de bit. Normalmente quem não está no meio da eletrônica não utiliza constantemente. No meu caso eu necessito usar essas máscaras para:

  1. Retirar informações de pacotes enviados por wireless(rádio ou ethernet)

imagine o seguinte pacote de 8 bits enviado por rádio de um controle remoto:

serie do controle número do botão
0010 0001

a informação enviada é 00100001 na variável x

para recuperar o número de série do controle e o botão pressionado no receptor eu faria:

int serie = x & 11110000
int bot = x & 00001111

Esse é um dos usos das máscaras. Existem vários.

Para melhor entendimento leia o artigo:

Olá,

Os números e operadores binários são bem fáceis de entender, mas difíceis de dominar a ponto de efetivamente utiliza-los para resolver problemas.
Eu por exemplo sou capaz de explicar passo-a-passo o que faz esse programa, mas não consigo fazer idéia de seu princípio ou que raciocínio levou à sua criação.

Mas o fato é que funciona! Fiz vários testes aqui e ele converte corretamente uma string binária para o número decimal correspondente.

Vamos ver um caso passo-a-passo:

Aplicando como entrada a string “0101” , correspondente ao numero 5 em decimal.

//Inicializa variavel ret com 0 (00000000 em binário)

//Agora ele vai iterar pelos caracteres da string binária ('0', '1', '0', '1').

//-> Posição 0 = '0'
//Primeira condição do IF: ret <<= 1  (Desloca 1 bit para a esquerda)
ret = ret << 1
ret = 00000000 << 1
ret = 00000000

//-> Posição 1 = '1'
// Segunda condição do IF: ret ^= 1; ret <<= 1;  (Faz um XOR com 1 e depois desloca 1 bit para a esquerda)
ret = ret ^ 00000001
ret = 00000000 ^ 00000001
ret = 00000001

ret = ret << 1
ret = 00000001 << 1
ret = 00000010

//-> Posição 2 = '0'
//Primeira condição do IF
ret = ret << 1
ret = 00000010 << 1
ret = 00000100

//-> Posição 3 = '1'
//Segunda condição do IF
ret = ret ^ 00000001
ret = 00000100 ^ 00000001
ret = 00000101

ret = ret << 1
ret = 00000101 << 1
ret = 00001010

//-> Após o loop desloca 1 bit para a direita
// ret >>= 1;
ret = 00001010 >> 1
ret = 00000101

//Retorna ret, que é igual a 00000101, que é igual a 5 - Correto!

Como eu disse, a mecânica da coisa é fácil, mas entender as propriedades dos binários a ponto de criar e compreender tal solução não é tarefa para qualquer um.

legal, não conhecia isso tambem

Quer ver mais um exemplo do que eu falei, sobre a diferença entre dominar os binários e só “conhecer as operações”?

Aconteceu neste tópico: http://www.guj.com.br/java/252035-resolvido-union-ou-semelhante-em-java

Certa hora sugeri a seguinte solução:

 private static int mergeBytes(byte b1, byte b2) {  
        final byte maskRemoveMinusSign = 127; //        01111111  
        final int maskAddMinusSign = 128;     // 000....10000000  
          
        int convertedB1;  
        if (b1 < 0) {  
            b1 = (byte) (b1 & maskRemoveMinusSign);  
            convertedB1 = b1;  
            convertedB1 = convertedB1 | maskAddMinusSign;  
        } else {  
            convertedB1 = b1;  
        }  
          
        int convertedB2;  
        if (b2 < 0) {  
            b2 = (byte) (b2 & maskRemoveMinusSign);  
            convertedB2 = b2;  
            convertedB2 = convertedB2 | maskAddMinusSign;  
        } else {  
            convertedB2 = b2;  
        }  
          
        convertedB1 = convertedB1 << 8;  
        return convertedB1 + convertedB2;  
    }  

Em seguida o entaglement colocou a seguinte, que faz exatamente a mesma coisa:

[code]

private static int mergeBytes(byte b1, byte b2) {
return ((b1 << 8) & 0xFF00) | (b2 & 0x00FF);
}
[/code] :shock:

Em um sistema de performance crítica, esse tipo de otimização faz toda a diferença.
É como diz aquela piadinha infame… existem 10 tipos de pessoas, as que conhecem binário e as que não :slight_smile:

[quote=gomesrod]Quer ver mais um exemplo do que eu falei, sobre a diferença entre dominar os binários e só “conhecer as operações”?

Aconteceu neste tópico: http://www.guj.com.br/java/252035-resolvido-union-ou-semelhante-em-java

Certa hora sugeri a seguinte solução:

 private static int mergeBytes(byte b1, byte b2) {  
        final byte maskRemoveMinusSign = 127; //        01111111  
        final int maskAddMinusSign = 128;     // 000....10000000  
          
        int convertedB1;  
        if (b1 < 0) {  
            b1 = (byte) (b1 & maskRemoveMinusSign);  
            convertedB1 = b1;  
            convertedB1 = convertedB1 | maskAddMinusSign;  
        } else {  
            convertedB1 = b1;  
        }  
          
        int convertedB2;  
        if (b2 < 0) {  
            b2 = (byte) (b2 & maskRemoveMinusSign);  
            convertedB2 = b2;  
            convertedB2 = convertedB2 | maskAddMinusSign;  
        } else {  
            convertedB2 = b2;  
        }  
          
        convertedB1 = convertedB1 << 8;  
        return convertedB1 + convertedB2;  
    }  

Em seguida o entaglement colocou a seguinte, que faz exatamente a mesma coisa:

[code]

private static int mergeBytes(byte b1, byte b2) {
return ((b1 << 8) & 0xFF00) | (b2 & 0x00FF);
}
[/code] :shock:

Em um sistema de performance crítica, esse tipo de otimização faz toda a diferença.
É como diz aquela piadinha infame… existem 10 tipos de pessoas, as que conhecem binário e as que não :-)[/quote]

igual o codigo inicial q poderia ser assim:

int binToDec(string bin){ int ret = 0; int i = 0; while(bin[i] == '0' || bin[i] == '1'){ ret <<= 1; if (bin[i] == '1') ret++; i++; } return ret; }

ou

int binToDec(string bin){ int ret = 0; int i = 0; while(bin[i] == '0' || bin[i] == '1'){ ret *= 2; if (bin[i] == '1') ret++; i++; } return ret; }

ambos ficaram + legíveis

[quote=GilsonNunes]
igual o codigo inicial q poderia ser assim:

int binToDec(string bin){ int ret = 0; int i = 0; while(bin[i] == '0' || bin[i] == '1'){ ret <<= 1; if (bin[i] == '1') ret++; i++; } return ret; }

ou

int binToDec(string bin){ int ret = 0; int i = 0; while(bin[i] == '0' || bin[i] == '1'){ ret *= 2; if (bin[i] == '1') ret++; i++; } return ret; }

ambos ficaram + legíveis[/quote]

Depois que você se acostuma usar, o bitwise sempre passa a ser a melhor solução porque a sintaxe acaba sendo mais limpa.

[code]#include <QtCore/QCoreApplication>
#include
#include

qint32 binToDec(const QString& val){
qint32 dec = 0;
for (int i = 0; i < val.size(); ++i) {
dec <<= 1;
if(val.at(i)==‘1’)
dec|=1;
}

return dec;

}

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

std::cout << binToDec("10000000")<< std::endl;

return a.exec();

}[/code]

Mas a questão de ganho de desempenho é uma ilusão, porque o assembly que o compilador gera é praticamente igual ao da outra solução.

Compartilhando um caso aqui também, tenho um algoritmo que converte um byte array GUID de um sistema externo para o padrão do Java, que é UUID:

public static UUID toUUID(byte[] byteArray) {
        long msb = 0;
        long lsb = 0;

        for (int i = 0; i &lt; 8; i++) {
            msb = (msb &lt;&lt; 8) | (byteArray[i] & 0xff);
        }

        for (int i = 8; i &lt; 16; i++) {
            lsb = (lsb &lt;&lt; 8) | (byteArray[i] & 0xff);
        }

        return new UUID(msb, lsb);
}

isto não é suficiente, pois se for fazer o uuid.toString() não bate com a string original do GUID. Rachei de procurar e acabei encontrando um algoritmo que faz um shift maluco, devido ao padrão do bit converter no Java ser little-endian. Enfim, dado que tenho o uuid na mão, o algoritmo continua assim:

// Gero o byte array do UUID.
long msb = uuid.getMostSignificantBits();
long lsb = uuid.getLeastSignificantBits();
byte[] originalBytes = new byte[16];

for (int i = 0; i &lt; 8; i++) {
    originalBytes[i] = (byte) (msb &gt;&gt; 8 * (7 - i));
}

for (int i = 8; i &lt; 16; i++) {
    originalBytes[i] = (byte) (lsb &gt;&gt; 8 * (7 - i));
}

// Faço o shift maluco para chegar no padrão GUID

byte[] reversedBytes = new byte[16];
// Troco os 4 primeiros de posição
reversedBytes[0] = originalBytes[3];
reversedBytes[1] = originalBytes[2];
reversedBytes[2] = originalBytes[1];
reversedBytes[3] = originalBytes[0];
// Troco o quinto com sexto
reversedBytes[4] = originalBytes[5];
reversedBytes[5] = originalBytes[4];
// Troco o sétimo com o oitavo
reversedBytes[6] = originalBytes[7];
reversedBytes[7] = originalBytes[6];
// Mantém o restante
System.arraycopy(originalBytes, 8, reversedBytes, 8, 16 - 8);