Operadores bit a bit ECMAScript

Os operadores de bits operam no nível inferior dos números (isto é, os 32 dígitos que representam o número).

Revisão de inteiros

Os inteiros ECMAScript têm dois tipos, inteiros assinados (permitem números positivos e negativos) e inteiros não assinados (permitem apenas números positivos). Em ECMAScript, todos os números literais são inteiros assinados por padrão, o que significa isso?

Os inteiros assinados usam 31 dígitos para representar o valor do inteiro e o 32º dígito para representar o sinal do inteiro, 0 para números positivos e 1 para números negativos. O intervalo de valores vai de -2147483648 a 2147483647.

Existem duas maneiras diferentes de armazenar inteiros assinados em formato binário, uma para números positivos e outra para números negativos. Os números positivos são armazenados em formato binário verdadeiro, onde cada um dos 31 primeiros dígitos representa o potência de 2, começando pelo primeiro dígito (o dígito 0), que representa 20O segundo dígito (o dígito 1) representa 21Os dígitos não usados são preenchidos com 0, ou seja, ignorados. Por exemplo, a figura a seguir mostra a representação do número 18.

Inteiros de 32 bits representados em binário

A versão binária de 18 usou apenas os primeiros 5 dígitos, que são os dígitos válidos deste número. Convertendo o número para uma string binária, podemos ver os dígitos válidos:

var iNum = 18;
alert(iNum.toString(2)); // Imprime "10010"

Este código apenas imprime "10010", não a representação de 32 bits de 18.Os outros dígitos não são importantes, porque apenas os primeiros 5 dígitos são necessários para determinar este valor decimal. Como mostrado na figura a seguir:

Inteiro de 5 bits em binário 18

Os números negativos também são armazenados como código binário, mas na forma de código de complemento binário. Os passos para calcular o código de complemento binário de um número têm três etapas:

  1. Determine a representação binária não negativa do número (por exemplo, para calcular o código de complemento binário de -18, é necessário determinar a representação binária de 18)
  2. Obtenha o código de complemento inverso, o que significa substituir 0 por 1 e 1 por 0
  3. Adicione 1 ao código de complemento inverso

Para determinar a representação binária de -18, primeiro é necessário obter a representação binária de 18, conforme mostrado a seguir:

0000 0000 0000 0000 0000 0000 0001 0010

A seguir, calcule o código de complemento inverso, conforme mostrado a seguir:

1111 1111 1111 1111 1111 1111 1110 1101

Por fim, adicione 1 ao código de complemento inverso, conforme mostrado a seguir:

1111 1111 1111 1111 1111 1111 1110 1101
                                      1
---------------------------------------
1111 1111 1111 1111 1111 1111 1110 1110

Portanto, a representação binária de -18 é 1111 1111 1111 1111 1111 1111 1110 1110. Lembre-se de que, ao lidar com inteiros assinados, os desenvolvedores não podem acessar o bit 31.

Curiosamente, quando um inteiro negativo é convertido para uma string binária, o ECMAScript não exibe o código de complemento binário, mas sim o valor absoluto do número seguido de um sinal negativo. Por exemplo:

var iNum = -18;
alert(iNum.toString(2)); // imprime "-10010"

Este código imprime "-10010", não o código de complemento binário, para evitar o acesso ao bit 31. Para simplificar, o ECMAScript lida com inteiros de uma maneira simples, permitindo que os desenvolvedores não se preocupem com seu uso.

Por outro lado, os inteiros sem sinal tratam o último bit como outro dígitto. Neste modelo, o 32º bit não representa o sinal do número, mas o valor 2.31Devido a esse bit adicional, o intervalo de valores dos inteiros sem sinal vai de 0 a 4294967295. Para inteiros menores que 2147483647, os inteiros sem sinal parecem ser iguais aos inteiros assinados, enquanto para inteiros maiores que 2147483647, o bit 31 (que é sempre 0 nos inteiros assinados) deve ser usado.

A conversão de inteiros sem sinal em strings retorna apenas os bits válidos.

Atenção:Todos os literais inteiros são armazenados por padrão como inteiros assinados. Apenas os operadores bitwise do ECMAScript podem criar inteiros sem sinal.

Operação bitwise NOT

A operação de bitwise NOT é representada pelo símbolo de negação (~), sendo uma das operações aritméticas binárias menos comuns no ECMAScript.

A operação bitwise NOT é um processo de três passos:

  1. Converter o operando em número de 32 bits
  2. Converter o número binário em seu complemento binário
  3. Converter o número binário em número flutuante

Por exemplo:

var iNum1 = 25; // 25 é igual a 00000000000000000000000000011001
var iNum2 = ~iNum1;	//Converter para 11111111111111111111111111100110
alert(iNum2); // saída "-26"

A operação bitwise NOT é basicamente negar o número e subtrair 1, então 25 se torna -26. Você também pode obter o mesmo resultado da seguinte maneira:

var iNum1 = 25;
var iNum2 = -iNum1 - 1;
alert(iNum2); // saída -26

Operação bitwise AND

A operação de bitwise AND é representada pelo símbolo (&) e opera diretamente sobre a forma binária do número. Ele alinha os dígitos de cada número e, em seguida, opera os dois dígitos na mesma posição usando as seguintes regras:

Bits do primeiro número Bits do segundo número Resultado
1 1 1
1 0 0
0 1 0
0 0 0

Por exemplo, para fazer a operação AND entre os números 25 e 3, o código é o seguinte:

var iResult = 25 & 3;
alert(iResult); // saída "1"

O resultado da operação AND entre 25 e 3 é 1. Por quê? Analisamos a seguir:

 25 = 0000 0000 0000 0000 0000 0000 0001 1001
  3 = 0000 0000 0000 0000 0000 0000 0000 0011
---------------------------------------------
AND = 0000 0000 0000 0000 0000 0000 0000 0001

Pode-se ver que, em 25 e 3, apenas um dígito (o bit 0) contêm 1, portanto, os outros dígitos geram 0, então o resultado é 1.

Operação bitwise OR

A operação de bitwise OR é representada pelo símbolo (|) e opera diretamente sobre a forma binária do número. Ao calcular cada dígitos, o operador OR adota as seguintes regras:

Bits do primeiro número Bits do segundo número Resultado
1 1 1
1 0 1
0 1 1
0 0 0

Ainda usando o exemplo do operador AND, faça a operação OR entre 25 e 3, o código é o seguinte:

var iResult = 25 | 3;
alert(iResult); // saída "27"

O resultado da operação OR entre 25 e 3 é 27:

25 = 0000 0000 0000 0000 0000 0000 0001 1001
 3 = 0000 0000 0000 0000 0000 0000 0000 0011
--------------------------------------------
OR = 0000 0000 0000 0000 0000 0000 0001 1011

Pode-se ver que, nos dois números, há 4 dígitos que contêm 1, esses dígitos são passados para o resultado. O código binário 11011 é igual a 27.

Operação de bit XOR

A operação de bit XOR é representada pelo sinal (^), claro, também opera diretamente na forma binária. XOR é diferente de OR, ele retorna 1 apenas quando um dos bits armazenados é 1. A tabela verdade é a seguinte:

Bits do primeiro número Bits do segundo número Resultado
1 1 0
1 0 1
0 1 1
0 0 0

Para operar XOR entre 25 e 3, o código é o seguinte:

var iResult = 25 ^ 3;
alert(iResult); // exibe "26"

O resultado do operador XOR entre 25 e 3 é 26:

 25 = 0000 0000 0000 0000 0000 0000 0001 1001
  3 = 0000 0000 0000 0000 0000 0000 0000 0011
---------------------------------------------
XOR = 0000 0000 0000 0000 0000 0000 0001 1010

Pode ser visto que, nos dois números, há 4 bits que armazenam 1, esses bits são passados para o resultado. O código binário 11010 é igual a 26.

Deslocamento à esquerda

O deslocamento à esquerda é representado por dois sinais menores (<<). Ele move todos os dígitos do número para a esquerda pela quantidade especificada. Por exemplo, se deslocar o número 2 (igual a 10 em binário) para a esquerda 5 vezes, o resultado é 64 (igual a 1000000).

var iOld = 2; // equivalente a 10 em binário
var iNew = iOld << 5; // equivalente a 1000000 em binário e 64 em decimal

Atenção:Ao deslocar os bits à esquerda, o número direito fica com 5 posições vazias. O deslocamento à esquerda preenche essas posições com 0, tornando o resultado um número de 32 bits completo.

Operação de deslocamento à esquerda do número 2

Atenção:O deslocamento à esquerda mantém o bit de sinal do número. Por exemplo, se deslocar -2 para a esquerda 5 vezes, o resultado é -64, não 64. “O sinal ainda é armazenado no 32º bit?” Sim, mas isso é feito no backstage do ECMAScript, e os desenvolvedores não podem acessar diretamente o 32º bit. Mesmo ao exibir o número negativo na forma de string binária, ele é mostrado com o sinal negativo (por exemplo, -2 será mostrado como -10).

Deslocamento à direita com sinal

O operador de deslocamento à direita com sinal é representado por dois sinais maiores (>>). Ele desloca todos os dígitos de um número de 32 bits para a direita, mantendo o sinal do número (positivo ou negativo). O operador de deslocamento à direita com sinal é exatamente o oposto do deslocamento à esquerda. Por exemplo, se deslocar 64 para a direita 5 vezes, o resultado será 2:

var iOld = 64; // igual a 1000000 em binário
var iNew = iOld >> 5; // igual a 10 em binário, 2 em decimal

Da mesma forma, o deslocamento de bits cria espaços vazios. Nesta vez, os espaços vazios estão no lado esquerdo do número, mas após o bit de sinal. O ECMAScript preenche esses espaços vazios com o valor do bit de sinal, criando um número completo, como mostrado na figura a seguir:

Operação de deslocamento à direita assinada do número 64

Deslocamento à direita sem sinal

O operador de deslocamento à direita sem sinal é representado por três大于符号(>>>),ele move todos os bits de um número de 32 bits à direita. Para números positivos, o resultado do deslocamento à direita sem sinal é o mesmo que o deslocamento à direita com sinal.

Usando o exemplo do deslocamento à direita com sinal, se 64 for deslocado 5 bits à direita, resultará em 2:

var iOld = 64; // igual a 1000000 em binário
var iNew = iOld >>> 5; // igual a 10 em binário, 2 em decimal

Para números negativos, a situação é diferente.

O deslocamento à direita sem sinal preenche todas as posições vazias com 0. Para números positivos, isso é semelhante ao deslocamento à direita com sinal, enquanto para números negativos, eles são tratados como números positivos.

Como o resultado do deslocamento à direita sem sinal é um número positivo de 32 bits, o deslocamento à direita sem sinal de um número negativo sempre resulta em um número muito grande. Por exemplo, se -64 for deslocado 5 bits à direita, resultará em 134217726. Como obter esse resultado?

Para fazer isso, é necessário converter esse número para uma forma equivalente sem sinal (apesar de o número em si ser de sinal), que pode ser obtida com o seguinte código:

var iUnsigned64 = -64 >>> 0;

Em seguida, use o toString() do tipo Number para obter sua representação binária real, usando a base 2:

alert(iUnsigned64.toString(2));

Isso gerará 11111111111111111111111111000000, que é a representação em complemento à direita do inteiro -64, mas é igual ao inteiro sem sinal 4294967232.

Por essa razão, é necessário usar o operador de deslocamento à direita sem sinal com cautela.