font ejemplo java bit-manipulation bitwise-operators bit-shift negative-number

ejemplo - Java: desplazamiento a la derecha en número negativo



text box java (3)

Debido a que en Java no hay tipos de datos sin signo, existen dos tipos de cambios a la derecha: desplazamiento aritmético >> y cambio lógico >>> . http://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html

El cambio aritmético >> mantendrá el bit de signo.

El cambio sin signo >>> no mantendrá el bit de signo (llenando así 0 s).

(imágenes de Wikipedia)

Por cierto, tanto el desplazamiento aritmético a la izquierda como el desplazamiento a la izquierda lógico tienen el mismo resultado, por lo que solo hay un desplazamiento a la izquierda << .

Estoy muy confundido sobre la operación de cambio a la derecha en el número negativo, aquí está el código.

int n = -15; System.out.println(Integer.toBinaryString(n)); int mask = n >> 31; System.out.println(Integer.toBinaryString(mask));

Y el resultado es:

11111111111111111111111111110001 11111111111111111111111111111111

¿Por qué derecho cambiar un número negativo por 31, no 1 (el bit de signo)?


Operator >> called Signed right shift , cambia todos los bits a la derecha un número específico de veces. Importante es >> llena el bit de signo más a la izquierda (Bit MSB más significativo) al bit más a la izquierda después del turno. Esto se denomina extensión de signo y sirve para conservar el signo de los números negativos cuando los desplaza hacia la derecha.

A continuación se muestra mi representación esquemática con un ejemplo para mostrar cómo funciona esto (para un byte):

Ejemplo:

i = -5 >> 3; shift bits right three time

La forma de complemento de cinco en dos es 1111 1011

Representación de la memoria:

MSB +----+----+----+---+---+---+---+---+ | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | +----+----+----+---+---+---+---+---+ 7 6 5 4 3 2 1 0 ^ This seventh, the left most bit is SIGN bit

Y a continuación, ¿cómo funciona? Cuando lo haces -5 >> 3

this 3 bits are shifted out and loss MSB (___________) +----+----+----+---+---+---+---+---+ | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | +----+----+----+---+---+---+---+---+ | / / | ------------| ----------| | | | ▼ ▼ ▼ +----+----+----+---+---+---+---+---+ | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | +----+----+----+---+---+---+---+---+ (______________) The sign is propagated

Aviso: los tres bits más a la izquierda son uno porque en cada bit de signo de cambio se conserva y cada bit también es correcto. He escrito que el signo se propaga porque todos estos tres bits se deben a un signo (pero no a datos).

También debido a tres cambios a la derecha, la mayoría de los tres bits son pérdidas.

Los bits entre las dos flechas derechas están expuestos desde bits anteriores en -5 .

Creo que sería bueno si escribo un ejemplo para un número positivo también. El siguiente ejemplo es 5 >> 3 y cinco es un byte es 0000 0101

this 3 bits are shifted out and loss MSB (___________) +----+----+----+---+---+---+---+---+ | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | +----+----+----+---+---+---+---+---+ | / / | ------------| ----------| | | | ▼ ▼ ▼ +----+----+----+---+---+---+---+---+ | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +----+----+----+---+---+---+---+---+ (______________) The sign is propagated

Ver de nuevo Escribo El signo se propaga , Así que más a la izquierda se deben firmar tres ceros para firmar el bit.

Entonces, esto es lo que el operador >> Signed right shift hace, conserva el signo del operando izquierdo.

[tu respuesta]
En su código, se desplaza -15 a la derecha durante 31 veces usando el operador >> , de modo que se liberan los 31 bits más a la derecha y los resultados son todos los bits 1 que en realidad son -1 en magnitud.

¿Notan que de esta manera -1 >> n es equivalente a no una declaración.
Creo que si uno hace i = -1 >> n debería ser optimizado a i = -1 por los compiladores de Java, pero eso es diferente

A continuación, sería interesante saber que en Java hay disponible un operador de desplazamiento a la derecha más >>> llamado Unsigned Right Shift . Y funciona lógicamente y llena cero desde la izquierda para cada operación de cambio. Por lo tanto, en cada cambio a la derecha, siempre obtiene un bit Cero en la posición más a la izquierda si usa el operador >>> desplazamiento a la derecha sin signo para los números Negativo y Positivo.

Ejemplo:

i = -5 >>> 3; Unsigned shift bits right three time

Y debajo está mi diagrama que demuestra cómo funciona la expresión -5 >>> 3 ?

this 3 bits are shifted out and loss MSB (___________) +----+----+----+---+---+---+---+---+ | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | +----+----+----+---+---+---+---+---+ | / / | ------------| ----------| | | | ▼ ▼ ▼ +----+----+----+---+---+---+---+---+ | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | +----+----+----+---+---+---+---+---+ (______________) These zeros are inserted

Y pueden notar: esta vez no escribo ese signo, los bits se propagan, pero en realidad >>> operador inserta ceros. Por lo tanto, >>> no conserva el signo, sino que realiza el desplazamiento lógico a la derecha.

En mi conocimiento, el desplazamiento a la derecha sin signo es útil en VDU (programación de gráficos), aunque no lo he usado, pero lo he leído en algún lugar del pasado.

Le sugiero que lea esto: la diferencia entre >>> y >> : >> es un desplazamiento aritmético correcto, >>> es un cambio lógico correcto.

Editar :

Algo interesante acerca del operador del operador sin signo de la derecha >>> .

  • El operador de desplazamiento a la derecha sin signo >>> produce un valor puro que es su operando izquierdo desplazado a la derecha con cero 0 extensión por el número de bits especificado por su operando de la derecha.

  • Como >> y << , operador >>> , el operador nunca lanza una excepción.

  • El tipo de cada operando del operador de desplazamiento a la derecha sin signo debe ser un tipo de datos entero o se produce un error de tiempo de compilación.

  • El operador >>> puede realizar conversiones de tipo en sus operandos; a diferencia de los operadores binarios aritméticos, cada operando se convierte de forma independiente. Si el tipo de un operando es byte, short o char, ese operando se convierte en int antes de que se calcule el valor del operador.

  • El tipo de valor producido por el operador de desplazamiento a la derecha sin signo es el tipo de su operando izquierdo. LEFT_OPERAND >>> RHIGT_OPERAND

  • Si el tipo convertido del operando izquierdo es int, solo se utilizan los cinco bits menos significativos del valor del operando derecho como la distancia de desplazamiento. ( eso es 2 5 = 32 bits = número de bit en int )
    Entonces, la distancia de cambio está en el rango de 0 a 31.

    Aquí, el valor producido por r >>> s es el mismo que:

    s==0 ? r : (r >> s) & ~(-1<<(32-s))

  • Si el tipo del operando izquierdo es largo, entonces solo se utilizan los seis bits menos significativos del valor del operando derecho como la distancia de desplazamiento ( es decir 2 5 = 64 bits = número de bit en largo )

    Aquí, el valor producido por r >>> s es el mismo que el siguiente:

    s==0 ? r : (r >> s) & ~(-1<<(64-s))

Una referencia interesante: [Capítulo 4] 4.7 Operadores de cambio


Porque >> se define como un desplazamiento aritmético a la derecha, que preserva el signo. Para obtener el efecto que espera, use un desplazamiento lógico a la derecha, el operador >>>.