2009-07-24 11 views
5

Esta es una duda con respecto a la representación de bits de enteros con signo. Por ejemplo, cuando quiere representar -1, es equivalente al complemento de 2 de (+1). Entonces -1 se representa como 0xFFFFFFF. Ahora cuando cambio mi número por 31 e imprimo el resultado, vuelve como -1.Bits representación de números negativos

signed int a = -1; 
printf(("The number is %d ",(a>>31));//this prints as -1 

Entonces, ¿alguien puede explicarme cómo se representan los bits para los números negativos?

Gracias.

+0

Mirándolo desde otro ángulo: piense en cualquier desplazamiento a la derecha N-bit (extendiendo la señal) dividiendo por 2^N, redondeando ABAJO (hacia menos infinito, no hacia 0.) Por lo tanto -1 desplazado a la derecha (con signo extensión) cualquier cantidad de veces seguirá produciendo -1. – vladr

Respuesta

10

Cuando el bit superior es cero, el número es positivo. Cuando es 1, el número es negativo.

Los números negativos desplazados a la derecha siguen desplazando un "1" como el bit más alto para mantener el número negativo. Es por eso que estás obteniendo esa respuesta.

Para obtener más información sobre el complemento de dos, vea this Stackoverflow question.


@Stobor señala que algunas implementaciones C podría cambiar 0 en el bit alto en lugar de 1. [verificado en Wikipedia.] En Java es fiable un desplazamiento aritmético.

Pero la salida dada por el que pregunta muestra que su compilador está haciendo un cambio aritmético.

+0

Pero si se imprime como -1, debe imprimirse como 1 rito, ya que el más alto pero es 1, que representa un número negativo. –

+1

@Nosredna: también debe mencionar que el comportamiento de rellenar con signo de bit es específico de la implementación. – Stobor

+0

Dado que representa un número negativo, ¿por qué imprimiría un número positivo? – Nosredna

1

Esta es una operación de desplazamiento aritmético que conserva el bit de signo y cambia la parte de mantisa de un número firmado.

aplausos

8

El estándar C deja indefinido si el desplazamiento a la derecha de un negativo (necesariamente Firmado) número entero turnos ceros (desplazamiento lógico a la derecha) o firmar bits (desplazamiento aritmético a la derecha) en el bit más significativo. Depende de la implementación elegir.

En consecuencia, el código portátil asegura que no realiza cambios a la derecha en números negativos. O bien convierte el valor en el valor sin signo correspondiente antes del cambio (que garantiza usar un desplazamiento lógico a la derecha, poniendo ceros en los bits vacíos), o asegura que el valor sea positivo, o que tolera la variación en la salida.

+0

O podría "o" en el bit superior (o bits) después del cambio. – Nosredna

+0

Muchas gracias por todas las respuestas. Supongo que aún no he borrado mi doyubt. ¿Es compilador o hardware específico? –

+2

@Maddy: depende del hardware y del compilador.Por ejemplo, si una CPU particular solo tiene desplazamiento lógico a la derecha (LSR) y no desplazamiento aritmético a la derecha (ASR), entonces los compiladores de esa máquina utilizarán el LSR y no el ASR inexistente. También depende del compilador; incluso si una máquina tiene tanto ASR como LSR, un escritor del compilador puede decidir utilizar LSR para cantidades tanto firmadas como sin firmar, por una serie de razones. Puede ser más rápido; podría ser consistente con otras plataformas donde también se ejecuta el mismo compilador; podría ser que a la persona que escribe el compilador no le guste ASR. –

1

Básicamente hay dos tipos de cambio a la derecha. Un desplazamiento a la derecha sin signo y un cambio a la derecha firmado. Un desplazamiento a la derecha sin signo desplazará los bits hacia la derecha, causando la pérdida del bit menos significativo, y el bit más significativo que se reemplazará con un 0. Con un desplazamiento a la derecha, los bits se desplazan hacia la derecha, causando la menor se perderá un bit significativo, y el bit más significativo a preservar. Un desplazamiento a la derecha firmado divide el número por una potencia de dos (que corresponde al número de lugares desplazados), mientras que un desplazamiento sin signo es una operación de cambio lógica.

El operador ">>" realiza un desplazamiento a la derecha sin signo cuando el tipo de datos en el que opera no está firmado, y realiza un cambio a la derecha firmado cuando el tipo de datos en el que opera está firmado. Entonces, lo que necesita hacer es convertir el objeto a un tipo entero sin signo antes de realizar la manipulación de bits para obtener el resultado deseado.

+0

No es necesariamente un 'shift firmado' para enteros con signo (aunque es muy común que se haga de esa manera) - depende del compilador y/o hardware. –

+0

Sí. Está bien. He estado programando durante tanto tiempo en computadoras portátiles/de escritorio/servidor que funcionan bien ejecutando alguna variante de x86 y compilando con GCC, que a menudo es fácil olvidar la diferencia entre qué suposiciones son razonables para la aplicación actual y qué estándar realmente garantías. –

0

EDIT: Cuando el siguiente fue escrito, el código en la pregunta fue escrito como:

unsigned int a = -1; 
printf(("The number is %d ",(a>>31));//this prints as -1 

Si unsigned int es de al menos 32 bits de ancho, entonces el compilador no es realmente permitió producir -1 como el resultado de eso (con la pequeña advertencia de que debe estar emitiendo el valor sin signo a int antes de pasarlo a printf).

Como a es un int sin signo, asignándole -1 debe darle el valor de UINT_MAX (como el valor no negativo más pequeño congruente con -1 módulo UINT_MAX + 1). Siempre que unsigned int tenga al menos 32 bits en su plataforma, el resultado de desplazar esa cantidad sin signo directamente a 31 será UINT_MAX dividido por 2^31, que debe ajustarse dentro de int. (Si unsigned int tiene 31 bits o menos, puede producir lo que quiera porque el resultado del cambio no está especificado).

Cuestiones relacionadas