Operadores de bits de ECMAScript

Los operadores de bits operan a nivel subyacente de los números (es decir, los 32 bits que representan el número).

Revisión de enteros

ECMAScript tiene dos tipos de enteros, es decir, enteros signados (que permiten números positivos y negativos) e enteros sin signo (que solo permiten números positivos). En ECMAScript, todos los números enteros literales son enteros signados por defecto, ¿qué significa esto?

Los enteros signados se representan con 31 bits para el valor del entero y con el bit 32 para el signo del entero, 0 para números positivos y 1 para números negativos. El rango de valores es de -2147483648 a 2147483647.

Se pueden almacenar enteros de forma binaria de dos maneras diferentes, una para números positivos y otra para números negativos. Los números positivos se almacenan en forma binaria verdadera, donde cada uno de los primeros 31 bits representa un poder de 2, comenzando por el primer bit (bit 0), que representa 20La segunda posición (bit 1) representa 21Los dígitos no utilizados se rellenan con 0, es decir, se ignoran. Por ejemplo, la siguiente imagen muestra la representación del número 18.

Entero de 32 bits representado en binario

La versión binaria de 18 solo utiliza los primeros 5 dígitos, que son los dígitos efectivos de este número. Al convertir el número en una cadena binaria, se pueden ver los dígitos efectivos:

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

Este código solo muestra "10010", en lugar de la representación de 32 bits de 18. Los otros dígitos no son importantes, ya que solo se utilizan los primeros 5 dígitos para determinar este número decimal. Como se muestra en la siguiente imagen:

Entero de 5 bits en binario 18

Los números negativos también se almacenan como códigos binarios, pero en forma de complemento a dos. Los pasos para calcular el complemento a dos de un número son tres:

  1. Determina la representación binaria no negativa de un número (por ejemplo, para calcular el complemento a dos de -18, primero debes determinar la representación binaria de 18)
  2. Obtén el complemento binario, es decir, cambia 0 por 1 y 1 por 0
  3. Suma 1 al complemento binario

Para determinar la representación binaria de -18, primero debe obtener la representación binaria de 18, como se muestra a continuación:

0000 0000 0000 0000 0000 0000 0001 0010

A continuación, calcula el complemento binario, como se muestra a continuación:

1111 1111 1111 1111 1111 1111 1110 1101

Finalmente, suma 1 al complemento binario, como se muestra a continuación:

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

Por lo tanto, la representación binaria de -18 es 1111 1111 1111 1111 1111 1111 1110 1110. Recuerda, al manejar enteros signados, los desarrolladores no pueden acceder al bit 31.

Curiosamente, al convertir un entero negativo en una cadena de caracteres binaria, ECMAScript no muestra el código de complemento a dos, sino que muestra el valor absoluto del número con un signo negativo antes del código binario estándar. Por ejemplo:

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

Este código produce la salida "-10010", no el código de complemento a dos, para evitar el acceso al bit 31. Para facilitar las cosas, ECMAScript maneja los enteros de una manera sencilla, haciendo que los desarrolladores no se preocupen por su uso.

Por otro lado, los enteros sin signo tratan el último bit como otro dígitو. En este esquema, el 32avo dígitо no representa el signo del número, sino el valor 231. Debido a este bit adicional, el rango de valores de los enteros sin signo es de 0 a 4294967295. Para enteros menores que 2147483647, los enteros sin signo parecen ser iguales a los enteros signados, mientras que para enteros mayores que 2147483647, se debe usar el bit 31 (en los enteros signados, este bit siempre es 0).

Al convertir un entero sin signo en una cadena de caracteres, solo se retornan sus bits efectivos.

Atención:Todos los literales enteros se almacenan por defecto como enteros signados. Solo los operadores de bits de ECMAScript pueden crear enteros sin signo.

Operación de bits NOT

La operación de bits NOT se representa con el símbolo de negación (~), y es uno de los operadores aritméticos binarios menos comunes en ECMAScript.

La operación de bits NOT es un proceso de tres pasos:

  1. Convertir el operando a un número de 32 bits
  2. Convertir un número binario a su complemento binario
  3. Convertir un número binario a un número de coma flotante

Por ejemplo:

var iNum1 = 25;		//25 es igual a 00000000000000000000000000011001
var iNum2 = ~iNum1;	//Convertir a 11111111111111111111111111100110
alert(iNum2);		//salida "-26"

La operación de bits NOT es básicamente obtener el negativo del número y restar 1, por lo que 25 se convierte en -26. También se puede obtener el mismo resultado con el siguiente método:

var iNum1 = 25;
var iNum2 = -iNum1 -1;
alert(iNum2);	//salida -26

Operación de bits AND

La operación de bits AND se representa por el símbolo (&) y opera directamente sobre la forma binaria de los números. Alinea cada dígito de cada número y luego realiza la operación AND sobre los dos dígitos en la misma posición según las siguientes reglas:

Dígitos del primer número Dígitos del segundo número Resultado
1 1 1
1 0 0
0 1 0
0 0 0

Por ejemplo, para realizar la operación AND entre los números 25 y 3, el código es el siguiente:

var iResult = 25 & 3;
alert(iResult);	//salida "1"

El resultado de la operación AND entre 25 y 3 es 1. ¿Por qué? Analicemos:

 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

Se puede ver que en 25 y 3, solo hay un dígito (dígito 0) que contiene 1, por lo que los otros dígitos generan 0, por lo que el resultado es 1.

Operación de bits OR

La operación de bits OR se representa por el símbolo (|) y opera directamente sobre la forma binaria de los números. Al calcular cada dígito, el operador OR sigue las siguientes reglas:

Dígitos del primer número Dígitos del segundo número Resultado
1 1 1
1 0 1
0 1 1
0 0 0

Aún utilizando el ejemplo del operador AND, se realiza la operación OR entre 25 y 3, el código es el siguiente:

var iResult = 25 | 3;
alert(iResult);	//salida "27"

El resultado de la operación OR entre 25 y 3 es 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

Se puede ver que en los dos números, hay 4 dígitos que contienen 1, estos dígitos se pasan al resultado. El código binario 11011 es igual a 27.

Operación de bits XOR

La operación de bits XOR se representa con el símbolo (^), por supuesto, también se realiza directamente en forma binaria. XOR es diferente de OR, solo devuelve 1 cuando hay un solo bit que almacena 1. La tabla de verdad es la siguiente:

Dígitos del primer número Dígitos del segundo número Resultado
1 1 0
1 0 1
0 1 1
0 0 0

Para realizar el operador XOR entre 25 y 3, el código es el siguiente:

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

El resultado del operador XOR entre 25 y 3 es 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

Se puede ver que en dos números, hay 4 dígitos que almacenan 1, estos dígitos se transmiten al resultado. El código binario 11010 es igual a 26.

Desplazamiento a la izquierda

El desplazamiento a la izquierda se representa con dos signos menores (<<). Mueve todos los dígitos del número hacia la izquierda en la cantidad especificada. Por ejemplo, al desplazar el número 2 (igual a 10 en binario) 5 lugares a la izquierda, el resultado es 64 (igual a 1000000 en binario):

var iOld = 2; // equivalente a binario 10
var iNew = iOld << 5; // equivalente a binario 1000000 decimal 64

Atención:Al desplazar los bits a la izquierda, se dejan 5 posiciones vacías a la derecha del número. El desplazamiento a la izquierda llena estas posiciones con 0, haciendo que el resultado sea un número de 32 bits completo.

Operación de desplazamiento a la izquierda del número 2

Atención:El desplazamiento a la izquierda mantiene el bit de signo del número. Por ejemplo, si se desplaza -2 5 lugares a la izquierda, se obtiene -64, no 64. ¿¿¿¿El bit de signo sigue almacenado en el 32avo lugar???. Sí, esto se realiza en el backend de ECMAScript, y los desarrolladores no pueden acceder directamente al 32avo bit. Incluso si se muestra el número negativo en forma de cadena binaria, se muestra con el signo negativo (por ejemplo, -2 se mostrará como -10).

Desplazamiento a la derecha con signo

El operador de desplazamiento a la derecha con signo se representa con dos signos mayores (>>). Mueve todos los dígitos de un número de 32 bits hacia la derecha en su conjunto, manteniendo el signo del número (positivo o negativo). El operador de desplazamiento a la derecha con signo es exactamente lo contrario al de desplazamiento a la izquierda. Por ejemplo, al desplazar 64 5 lugares a la derecha, se convierte en 2:

var iOld = 64; // equivalente a binario 1000000
var iNew = iOld >> 5; // equivalente a binario 10 decimal 2

Del mismo modo, el desplazamiento de bits causará espacios en blanco. Esta vez, los espacios en blanco están en el lado izquierdo del número, pero después del bit de signo. ECMAScript llena estos espacios en blanco con el valor del bit de signo, creando un número completo, como se muestra en la siguiente imagen:

Operación de desplazamiento a la derecha con signo del número 64

Desplazamiento a la derecha sin signo

El operador de desplazamiento a la derecha sin signo se representa por tres signos mayores (>>>), que desplaza todos los bits de un número sin signo de 32 bits a la derecha. Para números positivos, el resultado del desplazamiento a la derecha sin signo es igual al del desplazamiento a la derecha con signo.

Con el ejemplo de desplazamiento a la derecha con signo, si se desplaza 64 5 veces a la derecha, se convertirá en 2:

var iOld = 64; // equivalente a binario 1000000
var iNew = iOld >>> 5; // equivalente a binario 10 decimal 2

Para números negativos, la situación es diferente.

El desplazamiento a la derecha sin signo llena todos los espacios con ceros. Para números positivos, esto es lo mismo que el desplazamiento a la derecha con signo, mientras que para números negativos se trata como números positivos.

Dado que el resultado del desplazamiento a la derecha sin signo es un número positivo de 32 bits, el desplazamiento a la derecha sin signo de un número negativo siempre da un número muy grande. Por ejemplo, si se desplaza -64 5 veces a la derecha, se obtendrá 134217726. ¿Cómo se obtiene este resultado?

Para lograr esto, se necesita convertir este número a su forma equivalente sin signo (aunque el número en sí mismo es de signo), que se puede obtener con el siguiente código:

var iUnsigned64 = -64 >>> 0;

Luego, usa toString() del tipo Number para obtener su representación de bits verdadera, con una base de 2:

alert(iUnsigned64.toString(2));

Esto generará 11111111111111111111111111000000, que es la representación en complemento a dos del entero -64, aunque es igual al entero sin signo 4294967232.

Por esta razón, se debe tener cuidado al usar el operador de desplazamiento a la derecha sin signo.