2009-06-26 31 views
7

¿Por qué (-1 >> 1) resulta en -1? Estoy trabajando en C, aunque no creo que eso debería importar.(-1 >> 1) == -1 - ¿Por qué?

No puedo imaginar lo que me falta ...

Aquí es un ejemplo de un programa C que hace el Calc:

#include <stdio.h> 



int main() 
{ 
    int num1 = -1; 

    int num2 = (num1 >> 1); 

    printf("num1=%d", num1); 

    printf("\nnum2=%d", num2); 

    return 0; 
} 
+1

Igual que en php "echo -1 >> 1;" – merkuro

+0

también en python, y como dicen las respuestas, tiene sentido que los números negativos se llenen con un 1 para conservar el signo. –

Respuesta

23

Porque los enteros con signo están representados en la notación two's complement.

-1 será 11111111 (si fue un número de 8 bits).

-1 >> 1 evidentemente el signo se extiende para que permanezca 11111111.Este comportamiento depende del compilador, pero para Microsoft, al desplazar un número con signo a la derecha (>>), se copia el bit de signo, mientras que al desplazar un número sin signo hace que 0 se coloque en el bit situado más a la izquierda.

+4

Este es un comportamiento indefinido en C, nota. – bdonlan

+11

No es un comportamiento indefinido, está definido por la implementación si el bit de signo se transporta en un desplazamiento a la derecha firmado. – rlbond

+3

Para aquellos que quieran buscarlo, 6.5.7/5 en el estándar C99. –

5

Bit cambiando un número negativo es el comportamiento de implementación en C. Los resultados dependerán de su plataforma, y ​​teóricamente podría ser completamente absurdo. De la norma C99 (6.5.7.5):

El resultado de E1 E2 es E1 >> posiciones de bits de derecha desplazado E2. Si E1 tiene un tipo sin signo o si E1 tiene un tipo firmado y un valor no negativo, el valor del resultado es la parte integral del cociente de E1/ 2^E2. Si E1 tiene un tipo con signo y un valor negativo , el valor resultante es definido por la implementación.

La razón por la que esto sucede es muy probable porque su compilador usa la instrucción x86 SAR (Shift Arithmetic Right) para implementar >>. Esto significa que se producirá la extensión del signo: el bit más significativo se replicará en el nuevo MSB una vez que se haya cambiado el valor. Desde el intel manuals:

El desplazamiento aritmético a la derecha (SAR) y desplazamiento a la derecha lógica (SHR) instrucciones cambiar los bits del operando de destino a la derecha (hacia menos lugares significativos de bits). Para cada valor de desplazamiento, el bit menos significativo del operando de destino se desplaza en la bandera CF, y el bit más significativo se ajusta o se aclaró dependiendo de la instrucción tipo. La instrucción SHR borra el bit más significativo de (consulte la Figura 7-8 en Intel® 64 y IA-32 Architectures Software Developer's Manual, Volumen 1); La instrucción SAR establece o borra el bit más significativo para que corresponda al signo (la mayoría bit significativo) del valor original en el operando de destino. En efecto, la instrucción SAR llena valor desplazado de la posición vacía bit con el signo del valor unshifted (ver Figura 7-9 en el Intel® 64 y Manual IA-32 arquitecturas de software del desarrollador , Volumen 1)

+1

El pasaje citado indica que una operación como (10 >> -1) no está definida. El operando derecho es -1. – rlbond

+0

Ah, mi error. Arreglará. – bdonlan

+0

Es 6.5.7/5, no 6.5.7/3. –

3

Cuando se desplaza hacia la derecha y el bit más a la izquierda es un 1, algunas plataformas/compiladores traerán un 0 y algunos conservarán el 1 y harán que el nuevo bit más a la izquierda sea 1. Esto conserva el signo del número el número se mantiene negativo y se llama extensión de signo.

Verá la diferencia si prueba ((unsigned) -1) >> 1, que hará un cambio a la derecha sin signo y siempre cambiará en un bit de 0.

11

Un Arithmetic right shift preservará la señal cuando se cambia un signed number:

11111111 (-1) will stay 11111111 (-1) 

el contrario, un Logical right shift no va a conservar el signo:

11111111 (-1) will become 01111111 (127) 

Su código hace claramente un desplazamiento aritmético, por lo el bit de signo (MSB) se repite. Lo que hace el operador (>>) depende de los detalles de implementación de la plataforma que está utilizando. En la mayoría de los casos, es un cambio aritmético.

Además, tenga en cuenta que 11111111 puede tener dos significados diferentes según la representación. Esto también afecta la forma en que se cambiarán.

  • Si no firmado, 11111111 representa 255. El cambio hacia la derecha no va a conservar el signo desde el MSB no es un bit de signo.
  • Si está firmado, 11111111 representa -1. Aritméticamente desplazarlo a la derecha preservará el signo.
Cuestiones relacionadas