Operadores rápidos de desplazamiento de bits y bit a bit (con ejemplos)

En este tutorial, aprenderá sobre diferentes operaciones bit a bit en Swift. Se utilizan para el cálculo de nivel de bits en una expresión.

Un bit se usa para denotar un dígito binario. Un dígito binario puede tener dos valores posibles, 0 o 1. Como programador de nivel principiante, no tiene que trabajar con operaciones a nivel de bit.

Trabajar con tipos de datos primitivos como: entero, flotante, booleano, cadena, etc. es suficiente. Es posible que deba trabajar a nivel de bits cuando se trata de programación de bajo nivel.

Swift proporciona un amplio conjunto de operadores, además de los operadores básicos, para manipular bits. Estos operadores son similares a los operadores lógicos, excepto que trabajan en representaciones binarias de datos (bits).

Los operadores bit a bit son operadores que se utilizan para cambiar bits individuales de un operando. El operando es una variable o constante en la que se realiza la operación.

Todos los operadores bit a bit disponibles en swift se enumeran a continuación:

1. Operador NOT bit a bit

Está representado por un ~signo de tilde y se puede aplicar a un solo operando. Esto invierte todos los bits. es decir, cambia 1 a 0 y 0 a 1.

Si x es una variable / constante que contiene un valor binario, es decir, 0 o 1. La operación not bit a bit en la variable x se puede representar en la siguiente tabla:

NO
X ~ x
0 1
1 0

Ejemplo 1: operador NOT bit a bit para entero sin signo

 let initalNumber:UInt8 = 1 let invertedNumber = ~initalNumber print(invertedNumber) 

Cuando ejecute el programa anterior, la salida será:

 254

En el programa anterior, la declaración let initalNumber:UInt8 = 1es de tipo Unsigned int de tamaño 8 bits. Entonces, 1 en decimal se puede representar como 00000001en binario.

El operador not a nivel de bits cambia todo el bit de una variable o constante, el bit 0 se cambia a 1 y el 1 a 0. Por lo tanto, invertedNumber contiene bits 11111110. Después de convertirlo en decimal, se representa como 254. Entonces, la declaración print(invertedNumber)genera 254 en la pantalla.

También puede realizar un operador bit a bit directamente en los bits como:

Ejemplo 2: operador NOT bit a bit en bits

 let initialBits: UInt8 = 0b11111111 let invertedBits = ~initialBits print(invertedBits) 

Cuando ejecute el programa anterior, la salida será:

 0

initialBits contiene un valor binario 11111111que corresponde a 255 en decimal. Para representar el número en binario tenemos 0bcomo prefijo en el literal. Sin 0bun prefijo, lo tratará como un entero normal y obtendrá un error de desbordamiento (UInt8 puede almacenar números de solo 0 a 255).

Dado que hemos utilizado el operador not a nivel de bits, cambia todo el 1 a 0. Por lo tanto, la constante invertedBits contiene 00000000que es equivalente a 0 pulg UInt8.

Ejemplo 3: operador NOT bit a bit para entero con signo

 let initalNumber:Int = 1 let invertedNumber = ~initalNumber print(invertedNumber) 

Cuando ejecute el programa anterior, la salida será:

 -2

En el programa anterior, 1 en decimal se puede representar como 00000001en binario. El operador bit a bit cambia todo el bit de una variable o constante, el bit 0 se cambia a 1 y el 1 a 0. Por lo tanto, invertedNumber contiene bits 11111110. Esto debería mostrar 254 en la pantalla. Pero en cambio devuelve -2. Extraño, ¿verdad? Exploremos a continuación cómo sucedió esto.

let initalNumber:Int = 1es un int con signo que puede contener enteros tanto positivos como negativos. Es por eso que cuando aplicamos el operador not para un entero con signo, el binario devuelto también puede representar un número negativo.

¿Cómo interpretó el compilador -2 como 11111110 en binario?

El compilador usó el complemento de Dos para representar números enteros. Para obtener la notación negativa en complemento a dos de un entero, primero debe escribir el número en binario, luego invertir los dígitos y agregar uno al resultado.

Pasos para averiguar el complemento a dos de -2 :

  1. Escribe 2 en forma binaria: 00000010
  2. Invierte los dígitos. 0 se convierte en 1 y 1 se convierte en 0:11111101
  3. Suma 1: 11111110

Así es como el compilador interpreta el número binario 1111110como -2decimal. Pero, hay un pequeño giro que hizo el compilador que no notamos. También infirió el tipo de invertedNumber como Int8tipo.

Para entender esto, veamos un ejemplo a continuación:

 print(Int8(bitPattern: 0b11111110)) print(0b11111110)

Cuando ejecute el programa anterior, la salida será:

 -2 254

En el ejemplo anterior, el compilador trató el número binario a -2 en decimal solo para el entero de 8 bits con signo. Por lo tanto, la declaración print(Int8(bitPattern: 0b11111110))genera -2 en la pantalla.

Pero para el tipo de entero normal cuyo tamaño es de 32/64 bits y puede contener valores grandes, interpreta el valor como 254. Por lo tanto, la declaración print(0b11111110)genera 254 en la pantalla.

2. Operador AND bit a bit

Está representado por &dos operandos y se puede aplicar a ellos. El operador AND compara dos bits y devuelve 1 si ambos bits son 1; de lo contrario, devuelve 0.

Si xey son variables / constantes que tienen un valor binario, es decir, 0 o 1. La operación AND bit a bit en xey se puede representar en la tabla siguiente:

Y
X y x & y
0 0 0
0 1 0
1 1 1
1 0 0

Ejemplo 5: operación AND bit a bit

 let xBits = 0b10000011 let yBits = 0b11111111 let result = xBits & yBits print("Binary:",String(result, radix: 2)) print(result)

Cuando ejecute el programa anterior, la salida será:

 Binario: 10000011131 

En el programa anterior, la declaración let result = xBits & yBitscombina los bits de dos operandos xBits e yBits. Devuelve 1 si ambos bits son 1; de lo contrario, devuelve 0.

String(value , radix: )El inicializador se utiliza para representar números en diferentes sistemas numéricos. Si proporcionamos el valor de base 2. Convierte el número en un sistema numérico binario. De manera similar, podemos usar 16 para hexadecimal y 10 para decimal.

La declaración print("Binary:",String(result, radix: 2))salidas binarias: 10000011 en la pantalla. 10000011es equivalente a 131 en decimal, la declaración print(result)genera 131 en la consola.

3. Operador OR bit a bit

Se representa como |y se puede aplicar a dos operandos. El operador OR bit a bit compara dos bits y genera un resultado de 1 si una o más de sus entradas son 1 en caso contrario, 0.

Si xey son variables / constantes que tienen un valor binario, es decir, 0 o 1. La operación OR bit a bit en xey se puede representar en la siguiente tabla:

O
X y x | y
0 0 0
0 1 1
1 1 1
1 0 1

Ejemplo 6: operación OR bit a bit

 let xBits = 0b10000011 let yBits = 0b11111111 let result = xBits | yBits print("Binary:", String(result, radix: 2)) print(result) 

Cuando ejecute el programa anterior, la salida será:

 Binario: 11111111255 

En el programa anterior, la declaración let result = xBits | yBitscombina los bits de dos constantes xBits e yBits. Devuelve 1 si alguno de los bits es 1; de lo contrario, devuelve 0.

La declaración print("Binary:",String(result, radix: 2))genera Binary: 11111111 en la pantalla. Dado que, 11111111es equivalente a 255en decimal, la declaración print(result)genera 255 en la pantalla.

4. Operador XOR bit a bit

Se representa como ^y se puede aplicar a dos operandos. El operador XOR compara dos bits y genera un resultado de 1 si exactamente una de sus entradas es 1; de lo contrario, devuelve 0.

Si xey son variables / constantes que tienen un valor binario, es decir, 0 o 1. La operación XOR bit a bit en xey se puede representar en la siguiente tabla:

XOR
X y x y
0 0 0
0 1 1
1 1 0
1 0 1

Ejemplo 7: operación XOR bit a bit

 let xBits = 0b10000011 let yBits = 0b11111111 let result = xBits yBits print("Binary:", String(result, radix: 2)) print(result) 

Cuando ejecute el programa anterior, la salida será:

 Binario: 1111100 124 

En el programa anterior, la declaración let result = xBits yBitscombina los bits de dos constantes xBits e yBits. Devuelve 1 si exactamente uno de los bits es 1; de lo contrario, devuelve 0.

La instrucción print("Binary:",String(result, radix: 2))genera Binary: 1111100 (equivalente a 01111100) en la pantalla. Dado que, 1111100es equivalente a 124en decimal, la declaración print(result)genera 124 en la pantalla.

5. Operador de cambio bit a bit

Estos operadores se utilizan para mover todos los bits de un número hacia la izquierda o hacia la derecha en un cierto número de lugares y se pueden aplicar en un solo operando. Se representa como <<o >>.

Hay dos tipos de operadores de turnos:

Operador de desplazamiento a la izquierda bit a bit

  • Denotado como <<
  • Hace que los bits se muevan a la izquierda especificada por el número seguido de <<.
  • Las posiciones de bit que han sido desocupadas por la operación de cambio se llenan con ceros.
  • Desplazar los bits de un número entero a la izquierda en una posición duplica su valor

Ejemplo 8: operador de desplazamiento a la izquierda bit a bit

 let someBits:UInt8 = 0b11000100 print(someBits << 1) 

Cuando ejecute el programa anterior, la salida será:

 136

En el programa anterior, hemos utilizado el operador de cambio a la izquierda. Usar <<1 significa desplazar el bit en 1 a la izquierda. Los dígitos se desplazan una posición hacia la izquierda y el último dígito de la derecha se rellena con un cero.

También puede ver que el dígito que se desplaza "al final" del lado izquierdo se pierde. No vuelve a envolver desde la derecha. Al moverlo un bit a la izquierda, se elimina el 1 del binario y se agrega 0 a la derecha para completar el valor cambiado, y el resto de los otros bits se desplazan hacia la posición izquierda en 1.

Esto devuelve lo 10001000que es equivalente a 136in UInt8. Por lo tanto, la print(someBits << 1)declaración produce 136 en la pantalla.

Operador de desplazamiento a la derecha bit a bit

  • Denotado como >>
  • Hace que los bits se muevan a la derecha por el número seguido de >>
  • Para números sin signo, las posiciones de bit que se han dejado vacantes por la operación de cambio se rellenan con ceros.
  • Para números con signo (números que también pueden ser negativos), el bit de signo se usa para llenar las posiciones de bit vacías. En otras palabras, si el número es positivo, se usa 0, y si el número es negativo, se usa 1.
  • Si lo desplaza hacia la derecha una posición, su valor se reduce a la mitad.

Ejemplo 9: operador de desplazamiento a la derecha bit a bit para entero sin signo

 let someBits: UInt8 = 4 print(someBits>> 1) 

Cuando ejecute el programa anterior, la salida será:

 2

En el programa anterior, hemos utilizado el operador de desplazamiento a la derecha en un entero sin signo. Usar >>1 significa cambiar el bit en 1 a la derecha. Las posiciones de bit que han sido desocupadas por la operación de cambio siempre se llenan con cero en un entero sin signo.

Dado que, 4 se representa como 00000100en binario. Moviéndolo un bit a la derecha, devuelve lo 00000010que equivale a 2in UInt8. Por lo tanto, la print(someBits>> 1)declaración produce 2 en la pantalla.

Ejemplo 10: operador de desplazamiento a la derecha bit a bit para entero con signo

 let someBits:Int = -4 print(someBits>> 1) 

Cuando ejecute el programa anterior, la salida será:

 -2

En el programa anterior, hemos utilizado el operador de desplazamiento a la derecha en un entero sin signo. A diferencia de los números positivos, >>para los números negativos, se usa 1 para llenar el lugar vacante, en lugar de 0.

Dado que, -4se representa como 11111100en binario. Moviéndolo un bit a la derecha y colocando 1 en la posición vacante, devuelve lo 11111110que es equivalente a -2for Int8type. Por lo tanto, la print(someBits>> 1)declaración genera -2 en la pantalla.

Articulos interesantes...