Enteros con y sin signo

395

¿Es correcto decir que la diferencia entre un entero con signo y sin signo es:

  1. Sin signo puede contener un valor positivo mayor y ningún valor negativo.
  2. Unsigned usa el bit inicial como parte del valor, mientras que la versión firmada usa el bit más a la izquierda para identificar si el número es positivo o negativo.
  3. los enteros con signo pueden contener números positivos y negativos.

¿Alguna otra diferencia?

Shimmy Weitzhandler
fuente
66
Como 0 no es positivo ni negativo , es más apropiado usar el término valor no negativo en lugar de valor positivo para enteros sin signo.
Daniel

Respuestas:

344

Sin signo puede contener un valor positivo mayor y ningún valor negativo.

Si.

Unsigned usa el bit inicial como parte del valor, mientras que la versión firmada usa el bit más a la izquierda para identificar si el número es positivo o negativo.

Hay diferentes formas de representar enteros con signo. Lo más fácil de visualizar es usar el bit más a la izquierda como bandera ( signo y magnitud ), pero lo más común es el complemento a dos . Ambos están en uso en la mayoría de los microprocesadores modernos: el punto flotante usa signos y magnitud, mientras que la aritmética entera usa el complemento de dos.

los enteros con signo pueden contener números positivos y negativos.

si

Greg
fuente
No estoy seguro de si este es exactamente ese texto, pero encontré otro enlace. Vaya a la novena página del PDF (en realidad es la 38ª página del libro) y puede ver la sección denominada Representación de datos (Sección 1.3). Tiene la explicación de todas las cosas mencionadas anteriormente. lms.uop.edu.jo/lms/pluginfile.php/2420/mod_resource/content/1/…
WeirdElfB0y
92

Entraré en diferencias a nivel de hardware, en x86. Esto es principalmente irrelevante a menos que esté escribiendo un compilador o utilizando lenguaje ensamblador. Pero es bueno saberlo.

En primer lugar, x86 tiene soporte nativo para la representación complementaria de dos números con signo. Puede usar otras representaciones, pero esto requeriría más instrucciones y, en general, sería una pérdida de tiempo del procesador.

¿Qué quiero decir con "soporte nativo"? Básicamente quiero decir que hay un conjunto de instrucciones que usa para números sin signo y otro conjunto que usa para números con signo. Los números sin signo pueden ubicarse en los mismos registros que los números con signo, y de hecho puede mezclar instrucciones con y sin signo sin preocuparse por el procesador. Depende del compilador (o programador de ensamblaje) hacer un seguimiento de si un número está firmado o no, y usar las instrucciones apropiadas.

En primer lugar, los números del complemento a dos tienen la propiedad de que la suma y la resta son exactamente las mismas que para los números sin signo. No importa si los números son positivos o negativos. (Así que simplemente sigue adelante ADDy SUBtus números sin preocuparte).

Las diferencias comienzan a mostrarse cuando se trata de comparaciones. x86 tiene una manera simple de diferenciarlos: arriba / abajo indica una comparación sin signo y mayor / menor que indica una comparación con signo. (Por ejemplo, JAEsignifica "Saltar si es superior o igual" y no está firmado).

También hay dos conjuntos de instrucciones de multiplicación y división para tratar con enteros con y sin signo.

Por último: si desea verificar, por ejemplo, desbordamiento, lo haría de manera diferente para los números con y sin signo.

Artelius
fuente
¿Qué quiere decir con números sin signo y con signo? Lo que quiero preguntar es si escribo sin signo int a = 2 y con signo int b = 2, por lo que ambos están firmados o sin signo, ¿un número con signo o sin signo depende del tipo? lo asignamos o depende de si tiene signo negativo o no? Esto me ha estado molestando por un tiempo.
Suraj Jain
@SurajJain firmado y sin firmar referirse a tipos. Indican si es posible que una variable o expresión tenga un valor negativo.
Artelius
Tengo la siguiente duda, he hecho la pregunta, aún no hay una respuesta satisfactoria, échale un vistazo aquí, stackoverflow.com/questions/41399092/…
Suraj Jain
62

Solo preguntó sobre firmado y no firmado. No sé por qué la gente está agregando cosas adicionales en esto. Déjame decirte la respuesta.

  1. Sin signo: consta solo de valores no negativos, es decir, de 0 a 255.

  2. Firmado: consta de valores negativos y positivos, pero en diferentes formatos como

    • 0 a +127
    • -1 a -128

Y esta explicación es sobre el sistema de números de 8 bits.

Ashish Kumar
fuente
17

Solo algunos puntos para completar:

  • esta respuesta está discutiendo solo representaciones enteras. Puede haber otras respuestas para coma flotante;

  • La representación de un número negativo puede variar. El más común (de lejos, hoy es casi universal) en uso hoy es el complemento de dos . Otras representaciones incluyen el complemento de uno (bastante raro) y la magnitud con signo (muy poco común, probablemente solo se usa en piezas de museo) que simplemente usa el bit alto como un indicador de signo con los bits restantes que representan el valor absoluto del número.

  • Cuando se usa el complemento a dos, la variable puede representar un rango mayor (por uno) de números negativos que números positivos. Esto se debe a que el cero está incluido en los números 'positivos' (ya que el bit de signo no está configurado para cero), pero no los números negativos. Esto significa que el valor absoluto del número negativo más pequeño no se puede representar.

  • cuando se usa el complemento de uno o la magnitud con signo, puede tener cero representado como un número positivo o negativo (que es una de las dos razones por las que estas representaciones no se usan normalmente).

Michael Burr
fuente
Si escribo unsigned int a = -2, y firmé int b = -2, sería la representación subyacente igual, sé que no es bueno tener un número sin signo con un valor negativo, pero aún así si lo doy, ¿cuál será el representación subyacente?
Suraj Jain
1
Niggle menor: el signo y la magnitud se usan en coma flotante IEEE, por lo que en realidad es bastante común. :-)
alastair
14

De acuerdo con lo que aprendimos en clase, los enteros con signo pueden representar números positivos y negativos, mientras que los enteros sin signo solo no son negativos.

Por ejemplo, mirando un número de 8 bits :

valores sin signo0 a255

los valores con signo varían de -128a127

Ying Xiong
fuente
11

Todo excepto el punto 2 es correcto. Hay muchas notaciones diferentes para las entradas firmadas, algunas implementaciones usan la primera, otras usan la última y otras usan algo completamente diferente. Todo depende de la plataforma con la que esté trabajando.

Jasper Bekkers
fuente
¿Esa es la cosa little-endian y big-endian?
vIceBerg
little vs big endian tiene que ver con el orden de los bytes en la plataforma. Little endian puede hacer 0xFF 0xFE 0x7F mientras que big endian hará 0x7F 0xFE 0xFF.
Jasper Bekkers
10

Otra diferencia es cuando estás convirtiendo enteros de diferentes tamaños.

Por ejemplo, si está extrayendo un número entero de una secuencia de bytes (digamos 16 bits por simplicidad), con valores sin signo, podría hacer:

i = ((int) b[j]) << 8 | b[j+1]

(probablemente debería emitir el 2 nd bytes, pero supongo que el compilador hará lo correcto)

Con los valores firmados, debería preocuparse por la extensión del signo y hacer:

i = (((int) b[i]) & 0xFF) << 8 | ((int) b[i+1]) & 0xFF
Mike Gleen
fuente
5

En general, eso es correcto. Sin saber nada más acerca de por qué está buscando las diferencias, no puedo pensar en ningún otro diferenciador entre firmado y no firmado.

toddk
fuente
4

Más allá de lo que otros han dicho, en C, no se puede desbordar un entero sin signo; El comportamiento se define como módulo aritmético. Puede desbordar un entero con signo y, en teoría (aunque no en la práctica en los sistemas convencionales actuales), el desbordamiento podría desencadenar una falla (quizás similar a una falla dividida por cero).

Jonathan Leffler
fuente
1
Tenga en cuenta que el desbordamiento de enteros con signo desencadena un comportamiento indefinido, y los compiladores modernos son ultra agresivos al detectar esto y explotarlo para modificar su programa de maneras inesperadas pero técnicamente legítimas porque se les permite asumir que no ocurrirá un comportamiento indefinido, en términos generales. Esto es mucho más problemático ahora que hace 7 años.
Jonathan Leffler
4
  1. Sí, un entero sin signo puede almacenar un gran valor.
  2. No, hay diferentes formas de mostrar valores positivos y negativos.
  3. Sí, un entero con signo puede contener valores positivos y negativos.
Bhavesh
fuente
4

(en respuesta a la segunda pregunta) Al usar solo un bit de signo (y no el complemento de 2), puede terminar con -0. No muy bonita

Ryan Rodemoyer
fuente
Solo para agregar a esta respuesta, básicamente significa que 10 == 00 donde ambos números son base 2.
4

Los enteros con signo en C representan números. Si ay bson variables de tipos enteros con signo, el estándar nunca requerirá que un compilador haga que la expresión se a+=balmacene en aotra cosa que no sea la suma aritmética de sus valores respectivos. Para estar seguros, si la suma aritmética no encaja a, el procesador podría no ser capaz de colocarla allí, pero el estándar no requeriría que el compilador truncara o ajustara el valor, o hiciera cualquier otra cosa si los valores exceden Los límites para sus tipos. Tenga en cuenta que si bien el estándar no lo requiere, las implementaciones de C pueden atrapar desbordamientos aritméticos con valores firmados.

Los enteros sin signo en C se comportan como anillos algebraicos abstractos de enteros que son módulos congruentes con una potencia de dos, excepto en escenarios que involucran conversiones u operaciones con tipos más grandes. La conversión de un número entero de cualquier tamaño a un tipo sin signo de 32 bits producirá el miembro correspondiente a cosas que son congruentes con ese número entero mod 4.294.967.296. La razón por la que restar 3 de 2 produce 4,294,967,295 es que agregar algo congruente a 3 a algo congruente a 4,294,967,295 producirá algo congruente a 2.

Los tipos abstractos de anillos algebraicos son a menudo cosas útiles para tener; desafortunadamente, C usa la firma como factor decisivo para determinar si un tipo debe comportarse como un anillo. Peor aún, los valores sin signo se tratan como números en lugar de miembros del anillo cuando se convierten a tipos más grandes, y los valores sin signo más pequeños que intse convierten a números cuando se realiza una aritmética sobre ellos. Si ves un uint32_tigual 4,294,967,294, entonces v*=v;debería hacer v=4. Desafortunadamente, si intson 64 bits, entonces no se sabe qué v*=v;podría hacer.

Dado el estándar tal como es, sugeriría usar tipos sin signo en situaciones en las que uno quiera el comportamiento asociado con los anillos algebraicos, y los tipos con signo cuando quiera representar números. Es lamentable que C hiciera las distinciones de la manera en que lo hizo, pero son lo que son.

Super gato
fuente
3

Los enteros sin signo son mucho más propensos a atraparte en una trampa particular que los enteros con signo. La trampa proviene del hecho de que, si bien los puntos 1 y 3 anteriores son correctos, a ambos tipos de enteros se les puede asignar un valor fuera de los límites de lo que puede "retener" y se convertirá en silencio.

unsigned int ui = -1;
signed int si = -1;

if (ui < 0) {
    printf("unsigned < 0\n");
}
if (si < 0) {
    printf("signed < 0\n");
}
if (ui == si) {
    printf("%d == %d\n", ui, si);
    printf("%ud == %ud\n", ui, si);
}

Cuando ejecute esto, obtendrá el siguiente resultado a pesar de que ambos valores se asignaron a -1 y se declararon de manera diferente.

signed < 0
-1 == -1
4294967295d == 4294967295d
Mateo
fuente
0

La única diferencia garantizada entre un valor con signo y uno sin signo en C es que el valor con signo puede ser negativo, 0 o positivo, mientras que un sin signo solo puede ser 0 o positivo. El problema es que C no define el formato de los tipos (por lo que no sabe que sus enteros están en el complemento de dos). Estrictamente hablando, los dos primeros puntos que mencionó son incorrectos.

Más claro
fuente
0

Debe usar enteros sin signo al programar en sistemas integrados. En los bucles, cuando no se necesitan enteros con signo, el uso de enteros sin signo ahorrará la seguridad necesaria para diseñar dichos sistemas.

Fahad Naeem
fuente