2010-11-29 33 views
16

que tienen código siguiente:¿Por qué -1 >> 1 es -1? ¡Y 1 >> 1 es 0!

std::cout << (-10 >> 1) << std::endl; 
std::cout << (-9 >> 1) << std::endl; 
std::cout << (-8 >> 1) << std::endl; 
std::cout << (-7 >> 1) << std::endl; 
std::cout << (-6 >> 1) << std::endl; 
std::cout << (-5 >> 1) << std::endl; 
std::cout << (-4 >> 1) << std::endl; 
std::cout << (-3 >> 1) << std::endl; 
std::cout << (-2 >> 1) << std::endl; 
std::cout << (-1 >> 1) << std::endl; 

El resultado es:

-5 
-5 
-4 
-4 
-3 
-3 
-2 
-2 
-1 
-1 

Pero por qué?

-1 es 1111 1111 (por 1 byte), -1 >> 1 debe ser: 1011 1111 y no es -1 o 0! (signo de bit no se desplaza, lo sé)

¿Puede alguien explicarme cómo funciona esto?

+0

cada bit está desplazado, y no hay un bit de signo explícito en complemento a dos. – jalf

Respuesta

24

(operadores de desplazamiento) 5,8/3 estándar:

El valor 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 entera del cociente de E1 dividido por la cantidad de 2 elevado a la E2 poder. Si E1 tiene un tipo con signo y un valor negativo, el valor resultante está definido por la implementación.

Entonces, para la pregunta "¿por qué?", ​​La respuesta estándar es: ¿por qué no?

+8

La respuesta estándar es: "RTFM para su compilador" –

17

El desplazamiento a la derecha de un número negativo está definido por la implementación.

Las implementaciones que cambian en un bit de signo extendido al bit situado más a la izquierda funcionan como informaron.

En cuanto a por qué se hace de esta manera, se debe a que haga desplazamiento se puede utilizar para dividir por una potencia de 2 con ida y hacia negativo-infinito (por ejemplo, como floor()) el comportamiento de redondeo:

(-8 >> 2) == -2 
(-9 >> 2) == -3 
(-10 >> 2) == -3 
(-11 >> 2) == -3 
(-12 >> 2) == -3 

See this SO question.

3

-1 >> 1 debe ser: 1011 1111

Si eso fuera cierto, -10 >> 1 habría 10111011 == -69 en complemento a dos. ¡No es un resultado muy útil!

Aunque el comportamiento lingüístico no está definido (lo que el resultado, útil o de lo contrario no se puede confiar en ella), el comportamiento común (y la exhibida en este caso) es llevar a cabo "la extensión con signo".

No es cierto que el "bit de signo no se desplaza", que es cambiado, y el bit vacante se llena con un valor igual al bit de signo. Este comportamiento conserva el signo y proporciona la operación 'esperada' de división por dos que ha observado para todos los valores excepto -1. Para valores negativos, -1 es el "valor terminal" de un desplazamiento a la derecha, ya que el cero es para números positivos. Es decir, el desplazamiento a la derecha de un número negativo tiende a -1, y un número positivo tiende a cero.

3

En general, los cambios a la derecha se definen como "aritméticos" o "lógicos" La diferencia es que con un desplazamiento lógico a la derecha, el bit más a la izquierda siempre se pone a cero. Con un desplazamiento aritmético a la derecha, el bit más a la izquierda es una copia del valor anterior.

Por ejemplo, imaginemos que el valor es de solo 8 bits para facilitar el seguimiento. Entonces:

lógico:

0111 1111 >> 1 = 0011 1111 
1111 1111 >> 1 = 0111 1111 
1111 1110 >> 1 = 0111 1111 

Aritmética:

0111 1111 >> 1 = 0011 1111 
1111 1111 >> 1 = 1111 1111 
1111 1110 >> 1 = 1111 1111 

Un desplazamiento a la derecha aritmética es equivalente a dividir por 2 y el redondeo hacia el infinito negativo.

En C++, si el operador de desplazamiento a la derecha es lógico o aritmético es específico de la implementación. es decir, cada compilador puede decidir por sí mismo, probablemente sobre la base de lo que es más fácil de hacer, dando la arquitectura de la computadora en la que está trabajando.

Su afirmación de que el bit de signo no está desplazado es incorrecta. El bit de signo se desplaza al igual que todos los demás bits. La única pregunta es qué lo reemplaza.

Java tiene dos operadores diferentes de desplazamiento a la derecha: >> es aritmética y >>> es lógico.

+0

@laalto: Ah, gracias por la edición. Fue legible en mi pantalla mientras lo escribía. :-( – Jay

Cuestiones relacionadas