Los operadores de desplazamiento de bits hacen exactamente lo que su nombre implica. Cambian pedazos. Aquí hay una breve (o no tan breve) introducción a los diferentes operadores de turno.
Los operadores
>>
es el operador de desplazamiento a la derecha aritmético (o con signo).
>>>
es el operador de desplazamiento a la derecha lógico (o sin signo).
<<
es el operador de desplazamiento a la izquierda y satisface las necesidades de los cambios lógicos y aritméticos.
Todos estos operadores se puede aplicar a los valores enteros ( int
, long
, posiblemente short
y byte
o char
). En algunos idiomas, la aplicación de los operadores de desplazamiento a cualquier tipo de datos más pequeño que int
redimensiona automáticamente el operando para que sea un int
.
Tenga en cuenta que <<<
no es un operador, ya que sería redundante.
También tenga en cuenta que C y C ++ no distinguen entre los operadores de desplazamiento a la derecha . Proporcionan solo el >>
operador, y el comportamiento de desplazamiento hacia la derecha es la implementación definida para los tipos con signo. El resto de la respuesta usa los operadores C # / Java.
(En todas las implementaciones principales de C y C ++, incluidas GCC y Clang / LLVM, los >>
tipos con signo son aritméticos. Algunos códigos asumen esto, pero no es algo que el estándar garantice. Sin embargo, no está indefinido ; el estándar requiere implementaciones para definirlo como uno Sin embargo, los desplazamientos a la izquierda de los números con signo negativo es un comportamiento indefinido (desbordamiento de entero con signo). Por lo tanto, a menos que necesite un desplazamiento aritmético a la derecha, generalmente es una buena idea hacer su desplazamiento de bits con tipos sin signo).
Desplazamiento a la izquierda (<<)
Los enteros se almacenan, en la memoria, como una serie de bits. Por ejemplo, el número 6 almacenado como 32 bits int
sería:
00000000 00000000 00000000 00000110
Cambiar este patrón de bits a la posición de la izquierda ( 6 << 1
) daría como resultado el número 12:
00000000 00000000 00000000 00001100
Como puede ver, los dígitos se han desplazado hacia la izquierda en una posición, y el último dígito a la derecha se llena con un cero. También puede notar que desplazar a la izquierda es equivalente a la multiplicación por potencias de 2. Entonces, 6 << 1
es equivalente a 6 * 2
, y 6 << 3
es equivalente a 6 * 8
. Un buen compilador de optimización reemplazará las multiplicaciones con turnos cuando sea posible.
Desplazamiento no circular
Tenga en cuenta que estos no son turnos circulares. Desplazando este valor a la izquierda por una posición ( 3,758,096,384 << 1
):
11100000 00000000 00000000 00000000
resulta en 3,221,225,472:
11000000 00000000 00000000 00000000
El dígito que se desplaza "del final" se pierde. No se envuelve.
Desplazamiento lógico a la derecha (>>>)
Un desplazamiento lógico a la derecha es el inverso al desplazamiento a la izquierda. En lugar de mover los bits hacia la izquierda, simplemente se mueven hacia la derecha. Por ejemplo, cambiando el número 12:
00000000 00000000 00000000 00001100
a la derecha por una posición ( 12 >>> 1
) volverá nuestro 6 original:
00000000 00000000 00000000 00000110
Entonces vemos que desplazarse hacia la derecha es equivalente a la división por potencias de 2.
Los trozos perdidos se han ido
Sin embargo, un cambio no puede reclamar bits "perdidos". Por ejemplo, si cambiamos este patrón:
00111000 00000000 00000000 00000110
a la izquierda 4 posiciones ( 939,524,102 << 4
), obtenemos 2,147,483,744:
10000000 00000000 00000000 01100000
y luego retrocediendo ( (939,524,102 << 4) >>> 4
) obtenemos 134,217,734:
00001000 00000000 00000000 00000110
No podemos recuperar nuestro valor original una vez que hemos perdido bits.
Desplazamiento aritmético a la derecha (>>)
El desplazamiento aritmético a la derecha es exactamente como el desplazamiento lógico a la derecha, excepto que en lugar de rellenar con cero, rellena con el bit más significativo. Esto se debe a que el bit más significativo es el bit de signo , o el bit que distingue los números positivos y negativos. Al rellenar con el bit más significativo, el desplazamiento aritmético a la derecha conserva los signos.
Por ejemplo, si interpretamos este patrón de bits como un número negativo:
10000000 00000000 00000000 01100000
tenemos el número -2,147,483,552. Desplazar esto a la derecha 4 posiciones con el desplazamiento aritmético (-2,147,483,552 >> 4) nos daría:
11111000 00000000 00000000 00000110
o el número -134,217,722.
Entonces vemos que hemos preservado el signo de nuestros números negativos al usar el desplazamiento aritmético a la derecha, en lugar del desplazamiento lógico a la derecha. Y una vez más, vemos que estamos realizando una división por potencias de 2.