miércoles, 29 de junio de 2011

Representación De Los Enteros Con Signo En Complemento A Dos

Esta entrada pretende responder a una pregunta básica: ¿Cómo representan las computadoras a un número entero con signo?. Supongamos que nuestra computadora asigna 4 bits para la representación de estos números ( esto, desde luego, es una caricatura; en el lenguaje C el tamaño de un entero es por lo menos de 16 bits, aunque depende de la computadora, puede ver el tamaño de sus int usando este programa: Tipos de Datos en C; en tanto que en Java está fijo a 32 bits, lo cual es demasiado para nuestros fines didácticos). En una base binaria esto significa que podemos representar números del 0 ( 0000 ) al 15 (1111). Ahora bien, esos 16 símbolos distintos tienen que representar un rango de números positivos y negativos (presumiblemente de -7 a 7).

Atendiendo puramente a la representación a uno se le puede ocurrir lo siguiente:

Representación en la forma Magnitud con Signo:

Es, de cierta manera, lo más natural. Consiste en reservar la posición de la izquierda extrema para el signo con la convención de que 0 indica un entero positivo y 1 indica un entero negativo.

Binario       Magnitud con Signo

  0000               0
  0001               1
  0010               2
  0011               3
  0100               4
  0101               5
  0110               6
  0111               7
  1000              -0
  1001             - 1
  1010              -2
  1011             - 3
  1100             - 4
  1101             - 5
  1110             - 6
  1111             - 7


Representación en Complemento a Uno

Es un poco más ingeniosa y consiste en "invertir" la representación. Para obtener -3 es necesario tomar 3 ( 0011 ) y escribir un nuevo número cambiando los 1 por 0 y los 0 por uno, así se obtiene (1100)

  Binario       Complemento a Uno

  0000               0
  0001               1
  0010               2
  0011               3
  0100               4
  0101               5
  0110               6
  0111               7
  1000              -7
  1001              -6 
  1010              -5
  1011              -4
  1100              -3
  1101              -2
  1110              -1
  1111              -0


Inconvenientes de las representaciones Magnitud con Signo y Complemento a Uno:

Ahora bien, este par de representaciones tiene algunos problemas: existen 2 símbolos distintos para el 0 y no permiten operar aritméticamente.

En la representación Magnitud con Signo, intentemos sumar 7 + (-2)

0111 (7)
1010 (-2)
___________
0001 (1)


Pero 7 - 2 != 1

En la representación Complemento a Uno

0111 (7)
1101 (-2)
___________
0100 (4)

Pero 7 - 2 != 4 Observe además que aquí ha ocurrido un "acarreo", el resultado de la suma es 10100, pero como usamos 4 bits eso no importa, ya que tomamos los primeros 4 valores de la derecha.

Aún con estos problemas es posible, y se ha hecho en el pasado, usar estas representaciones para almacenar números con signo en computadoras electrónicas. Sin embargo, hacer hardware para sumar (diseñar circuitos lógicos) es demasiado complicado en estos casos. Por eso, actualmente la gran mayoría de las computadoras usan la siguiente representación.

Representación en Complemento a Dos:

Como se ha visto, es muy deseable que la representación sea tal que cuando se suma un número positivo con su negativo, el resultado sea 0000.  Por ejemplo, ya que 5 se representa como 0101, a -5 se le asigna 1011, ya que la suma es 10000, la cual truncada a los primeros 4 bits, da 0 (0000). Usando esto como guía es posible establecer la siguiente tabla


  Binario      Complemento a Dos

  0000               0
  0001               1
  0010               2
  0011               3
  0100               4
  0101               5
  0110               6
  0111               7
  1000              -8
  1001              -7
  1010              -6
  1011              -5
  1100              -4
  1101              -3
  1110              -2
  1111              -1

Además, algo muy importante, podemos ver que en este caso si se ordenan los números de -7 a 7, el siguiente se obtiene sumando 1 al número anterior, por lo mismo al símbolo 1000 se le asigna el valor -8, que encaja perfectamente.

 Binario      Complemento a Dos

  1000              -8
  1001              -7
  1010              -6
  1011              -5
  1100              -4
  1101              -3
  1110              -2
  1111              -1
  0000               0
  0001               1
  0010               2
  0011               3
  0100               4
  0101               5
  0110               6
  0111               7

Esto garantiza que la suma de números dentro del rango de -8 a  7, se hará de forma correcta.  Obsérvese que esta representación es muy parecida a la Representación en Complemento a Uno, y que, como algoritmo, para encontrar el negativo de un número, digamos 5 (0101) sólo es necesario encontrar el Complemento a Uno, cambiando 1 por 0 y viceversa, (1010) y sumar 0001, con lo cual obtenemos -5 (1011). Las sumas producen "acarreo", por ejemplo -3  (1101) -3 (1101) es igual a    11010, pero como sólo estamos trabajando en 4 bits, el resultado se trunca y se obtiene -6 (1010), lo cual es correcto. El acarreo es lo que origina el desbordamiento de la memoria en la suma de dos numeros muy grandes. Si en java, o en cualquier otro lenguaje, se suma un par de enteros muy grandes (2147483640 + 2147483640) se obtiene la respuesta -1932700016. Esta no es, desde luego, la respuesta correcta. Lo que ha pasado es que los números están en el límite superior de lo que puede almacenar un int en java. El signo menos viene porque en la entrada extrema izquierda, el bit 32, hay un 1 (que indica número negativo) en lugar de un 0 (que indica número positivo) así pues, la suma se trunca, se convierte a decimal y se cambia de signo. Creo que este ejemplo en particular muestra la importancia de saber algo acerca de la forma en que se almacenan los enteros en una computadora.
El uso de la Representación en Complemento a Dos es, por cierto, lo que hace que, por ejemplo, en Java los tipos int varíen en un rango de -2147483648 a  2147483647, se reserva el bit 32 para el signo y las siguientes magnitudes dependen de los 31 bits restantes  (2^31 = 2147483648). Si usted, como yo, se había preguntado alguna vez por qué el rango no es simétrico, o por qué  no va de -2147483647 a 2147483648, espero que esta entrada le haya servido para resolver esa duda.
______________________________________________________________________________________________
Lo que aprendió:
La representación de los números con signo en la forma Magnitud con Signo
La representación de los números con signo en Complemento a 1
La representación de los números con signo en Complemento a 2
______________________________________________________________________________________________
Esta entrada forma parte del Curso de C con Programas Explicados Línea por Línea
Índice
Entrada Anterior
Entrada Siguiente

No hay comentarios:

Publicar un comentario en la entrada

Related Posts Plugin for WordPress, Blogger...