Números con y sin signo

17

¿Cómo diferenciaría la ALU en un microprocesador entre un número con signo, -7 que se denota con 1111 y un número sin signo 15, también con 1111?

noorav
fuente
3
Consulte la respuesta de la pregunta relacionada: cs.stackexchange.com/a/30047/28999 . Por cierto, el signo -7 no se representa como 1111. Eso es -1. Entonces, por ejemplo, 1111 - 0001 = 1110 tanto en el caso firmado como sin firmar (-2 vs 14)
Albert Hendriks
2
@AlbertHendriks Para ser justos, algunas computadoras antiguas usan una "representación de magnitud de signo" (un bit de signo y bits de magnitud ), y todavía usamos ese estilo para, por ejemplo, flotadores IEEE. Son simplemente poco elegantes y difíciles de trabajar en comparación con el complemento de dos. n1
Draconis
1
La principal diferencia radica en cómo se comportan los operadores de mayor / menor que, y si el desplazamiento a la derecha se completa con el bit más alto. Cuando realmente multiplicas y divides, el resultado es el mismo.
Rob
2
@Rob Eso no es del todo correcto. Sumar, restar y multiplicar son todos iguales entre sin signo y dos complementarios, suponiendo que sus entradas y salidas sean del mismo tamaño. La división no es la misma 6/2 es 3, pero -2/2 es -1. Y muchas CPU tienen instrucciones de multiplicación en las que las dos entradas son de tamaño idéntico, pero la salida es el doble del tamaño, en cuyo caso los signos sin signo y dos complementarios tampoco son iguales.
kasperd

Respuestas:

14

La respuesta corta y simple es: no lo hace. Ninguna CPU mainstream moderna ISA funciona de la manera que piensas.

Para la CPU, es solo un patrón de bits. Depende de usted, el programador, hacer un seguimiento de lo que significa ese patrón de bits.

En general, los ISA no distinguen entre diferentes tipos de datos, cuando se trata de almacenamiento. (Ignorando los registros de propósito especial, como los registros flotantes en una FPU). Es solo un patrón de bits sin sentido para la CPU. Sin embargo, las NIA hacer tienen diferentes tipos de instrucciones que pueden interpretar el patrón de bits de diferentes maneras. Por ejemplo, instrucciones aritméticas tales como MUL, DIV, ADD, SUBinterpretan el patrón de bits como una especie de número, mientras que las instrucciones lógicas, tales como AND, OR, XORinterpretarlo como una matriz de booleanos. Por lo tanto, depende del programador (o el autor del intérprete o compilador si usa un lenguaje de nivel superior) elegir las instrucciones correctas.

Es muy posible que haya instrucciones separadas para números con y sin signo, por ejemplo. Algunos ISA también tienen instrucciones para la aritmética con decimales codificados en binario.

Sin embargo, tenga en cuenta que escribí "ISA mainstream moderna" arriba. De hecho, existen ISA no convencionales o históricas que funcionan de manera diferente. Por ejemplo, tanto el CISC ISA original de 48 bits del IBM AS / 400 como el RISC ISA actual de 64 bits basado en POWER del sistema ahora llamado IBM i, distinguen entre punteros y otros valores. Los punteros siempre están etiquetados e incluyen información de tipo y gestión de derechos. La CPU sabe si un valor es un puntero o no, y solo el núcleo privilegiado de i / OS puede manipular los punteros libremente. Las aplicaciones de usuario solo pueden manipular los punteros que poseen para apuntar a la memoria que poseen utilizando una pequeña cantidad de instrucciones seguras.

También hubo algunos diseños históricos de ISA que incluían al menos alguna forma limitada de reconocimiento de tipos.

Jörg W Mittag
fuente
Tenga en cuenta que el bytecode de Java también cuenta como ISA. Y prácticamente le importan los tipos de datos ...
John Dvorak
El bytecode de Java cuenta como un ISA, en el sentido de que se ha implementado en silicio. Sin embargo, la comprobación de tipo básico de este tipo es la comprobación realizada por el cargador de clases, por lo que los tipos pueden ignorarse en su mayoría en tiempo de ejecución. Y, por supuesto, el código de bytes de Java no tiene tipos sin signo en primer lugar.
Seudónimo
@Pseudonym: Bueno, técnicamente, no tiene char, que es un tipo sin signo de 16 bits. Por supuesto, todavía no hay instrucciones aritméticas sin signo en el código de bytes de Java, ya que cualquier charvalor se promueve automáticamente int(con signo de 32 bits) para aritmética.
Ilmari Karonen
42

Versión corta: no lo sabe. No hay forma de saberlo.

Si 1111representa -7, entonces tiene una representación de magnitud de signo , donde el primer bit es el signo y el resto de los bits son la magnitud. En este caso, la aritmética es algo complicada, ya que un complemento sin signo y un complemento con signo utilizan una lógica diferente. Por lo tanto, probablemente tenga un SADDy un UADDcódigo de operación, y si elige el incorrecto, obtendrá resultados sin sentido.

Sin embargo, más a menudo 1111representa -1, en lo que se llama una representación de complemento a dos . En este caso, a la ALU simplemente no le importa si los números están firmados o no. Por ejemplo, tomemos la operación de 1110 + 0001. En aritmética con signo, esto significa "-2 + 1", y el resultado debería ser -1 ( 1111). En aritmética sin signo, esto significa "14 + 1", y el resultado debe ser 15 ( 1111). Por lo tanto, la ALU no sabe si desea un resultado firmado o sin firmar, y no le importa. Simplemente hace la adición como si no estuviera firmada, y si desea tratar eso como un entero firmado después, eso depende de usted.

EDITAR: Como Ruslan y Daniel Schepler señalan con razón en los comentarios, algunos operandos todavía necesitan versiones separadas firmadas y sin firmar, incluso en una máquina con dos complementos. La suma, la resta, la multiplicación, la igualdad y todo eso funciona bien sin saber si los números están firmados o no. Pero la división y cualquier comparación mayor que / menor que deben tener versiones separadas.

EDITAR EDITAR: También hay algunas otras representaciones, como el complemento de uno , pero básicamente ya no se usan más, por lo que no debería preocuparse por ellas.

Draconis
fuente
Ah, te tengo. Gracias por esto :)
noorav
10
En la representación del complemento a dos, tres operaciones aritméticas son independientes de la firma: suma, resta y multiplicación (con producto de la misma longitud que los operandos). Solo la división debe manejarse de manera diferente para los operandos firmados.
Ruslan
44
También hay comparación: < <= >= >son diferentes para operandos con ==y sin signo, y !=son independientes de la firma.
Daniel Schepler
La multiplicación a menudo tiene variedades con y sin signo: 0xFFFFFFFF * 0xFFFFFFFF es 0xFFFFFFFE00000001 si no está firmado y 0x0000000000000001 si está firmado. Los procesadores como Intel devuelven el resultado en 2 registros, y el registro superior difiere para firmado y no firmado. El registro inferior es 1 en ambas situaciones.
Rudy Velthuis
9

Una de las grandes ventajas de las matemáticas de complemento a dos, que utilizan todas las arquitecturas modernas, es que las instrucciones de suma y resta son exactamente las mismas para los operandos con signo y sin signo.

Muchas CPU ni siquiera tienen instrucciones de multiplicación, división o módulo. Si lo hacen, deben tener formas separadas y firmadas de la instrucción, y el compilador (o el programador en lenguaje ensamblador) elige la apropiada.

Las CPU también generalmente tienen diferentes instrucciones para las comparaciones con o sin firma. Por ejemplo, x86 podría seguir a CMPcon JL(Saltar si es menor que) si la comparación debe estar firmada, o JB(Saltar si está debajo) si la comparación debe estar sin firmar. Nuevamente, el compilador o el programador elegirían la instrucción correcta para el tipo de datos.

Algunas otras instrucciones a menudo vienen en variantes con signo y sin signo, como desplazamiento a la derecha o cargar un valor en un registro más amplio, con o sin extensión de signo.

Davislor
fuente
1
Incluso la multiplicación es la misma para enteros sin signo y con signo (complemento de dos), siempre que no necesite el resultado para tener más bits que las entradas . Sin embargo, si está haciendo algo como la multiplicación 8 × 8 → 16 bits (o 16 × 16 → 32 bits, etc.), debe firmar extender las entradas (o los resultados intermedios) .
Ilmari Karonen
@IlmariKaronen Esto es cierto; ARM A32 / A64 son conjuntos de instrucciones que tienen muchas formas de la instrucción de multiplicación, incluida la suma-suma agnóstica de signos que escribe solo los bits de orden inferior, pero también smulhy umulhque devuelve solo los bits superiores de la multiplicación y las instrucciones con y sin signo que devuelve el resultado en un registro dos veces más ancho que los operandos de origen.
Davislor
6

No lo hace. El procesador se basa en el conjunto de instrucciones para decirle qué tipo de datos está mirando y dónde enviarlos. No hay nada acerca de 1s y 0s en el operando en sí mismo que pueda indicar de forma inherente a la ALU si los datos son char, float, int, firmado int, etc. Si ese 1111 va a un circuito eléctrico que espera un complemento de 2s, va para ser interpretado como un complemento 2s.

Jay Speidell
fuente
No hay tal cosa como un char a nivel de hardware. Quizás alguna vez, en los días de las teleimpresoras mecánicas. Pero hoy, a chares solo un número en lo que respecta al hardware. La razón por la que diferentes números corresponden a diferentes formas de letras en su pantalla es que esos números se utilizan para seleccionar diferentes mapas de bits o diferentes rutinas de dibujo de una tabla grande (es decir, de una "fuente").
Solomon Slow
3

Me gustaría agregar una adición a las respuestas ya hechas:

En la mayoría de las otras respuestas, se observa que en la aritmética de dos complementos, el resultado es el mismo para números con signo y sin signo:

-2 + 1 = -1     1110 + 0001 = 1111
14 + 1 = 15     1110 + 0001 = 1111

Sin embargo , hay excepciones:

Division:
  -2 / 2 = -1     1110 / 0010 = 1111
  14 / 2 = 7      1110 / 0010 = 0111
Comparison:
  -2 < 2 = TRUE   1110 < 0010 = TRUE
  14 < 2 = FALSE  1110 < 0010 = FALSE
"Typical" (*) multiplication:
  -2 * 2 = -4     1110 * 0010 = 11111100
  14 * 2 = 28     1110 * 0010 = 00011100

(*) En muchas CPU, el resultado de una multiplicación de dos números de n bits es (2 * n) bits de ancho.

Para tales operaciones, las CPU tienen diferentes instrucciones para aritmética con y sin signo.

Esto significa que el programador (o el compilador) debe usar otras instrucciones para aritmética con y sin signo.

La CPU x86, por ejemplo, tiene una instrucción llamada divpara hacer una división sin signo y una instrucción llamada idivpara hacer una división con signo.

También hay diferentes instrucciones "condicionales" (saltos condicionales, set-bit-on-condition), así como instrucciones de multiplicación para aritmética con y sin signo.

Martin Rosenau
fuente