Mostrando las entradas con la etiqueta complemento. Mostrar todas las entradas
Mostrando las entradas con la etiqueta complemento. Mostrar todas las entradas

lunes, 23 de mayo de 2016

Cómo expresar números negativos en complemento a la base sin que se te vuele el peluquín


Existe una razón por la que el sistema decimal nos resulta tán cómodo, después de todo contamos con diez dedos y pasamos los primeros años de nuestra vida midiendo años en término de ellos. Pero como la amiga CPU necesita ver las cosas en binario, más de una vez al programar en bajo nivel debemos transformar un valor a ceros y unos. Hasta ahí es feo, pero después de un poco de práctica se hace más fácil. Sin embargo expresar números negativos en binario es un par de vueltas más feo que eso. ¿Cómo podemos hacerlo -un poco- más fácil? En lugar de las metodologías tradicionales, les propongo este sistema, el cual requiere hacer algunos cálculos mentales, los que estoy seguro de que su cerebro podrá procesar sin levantar temperatura.
Este es el método que aprendí en el libro de Thomas Floyd (Fundamentos de sistemas digitales) para representar números enteros negativos en complemento a la base en 8 bits. 
Cuando representamos enteros sin signo en 8 bits, la vida es fácil, solo debemos recordar los pesos de cada dígito:

128 64 32 16 8 4 2 1

Se trata de las potencias enteras de dos, que justamente por ello tienen una relación fácil de recordar entre valores consecutivos (dependiendo de dónde se empiece, es el doble o la mitad). Para representar números sin signo rápidamente, podemos emplear el método por inspección (manera elegante de decir medio mentalmente, medio a ojo). 
Pongamos un ejemplo cualquiera: el 96.
1. Antes que nada constatamos que el número a representar entre en el rango admitido de 8 bits sin signo (0;255). El 96 cumple la condición, así que continuamos.
2. Luego vemos si alguno de los pesos binarios de cada posición supera al número. 96 es mayor a todos los pesos salvo al más pesado: 128. Por tanto en 128 va un cero:

128 64 32 16 8 4 2 1
   0  ?  ?  ?  ? ? ? ?  

El resto aun no sabemos (por eso el signo de interrogación).
Si hubiera más valores de pesos que superan al número objetivo, podemos completar con ceros.
3. Cuando hallamos el mayor peso que no supera al número objetivo (o que lo iguala) le ponemos un uno. En nuestro ejemplo 64 es ese número:

128 64 32 16 8 4 2 1
   0  1  ?  ?  ? ? ? ?  

Ahora tenemos que restar (mentalmente en un mundo ideal) 96 - 64. El resultado es 32.
4. Repetimos el paso anterior con el siguiente peso. Si el peso supera al número, va un cero. Si no lo supera, va un uno y restamos el peso del resto del objetivo. Casualmente en este ejemplo nos quedaron 32 y el siguiente peso es 32. Así que va un 1 en el peso 32 y la resta nos da cero. Por lo tanto el resto de los pesos son cero (no queda resto para representar):

128 64 32 16 8 4 2 1
   0  1  1  0  0 0 0 0  


Repitamos el procedimiento para un número distinto, por ejemplo el 172. En este caso 128 es menor a 172, por tanto ponemos un 1 en 128:

128 64 32 16 8 4 2 1
   1  ?  ?  ?  ? ? ? ?  

La parte difícil: restamos mentalmente 172-128... es 44. El siguiente peso (64) es mayor a 44, por ende ponemos un cero:
128 64 32 16 8 4 2 1
   1  0  ?  ?  ? ? ? ?   

El siguiente peso (32) es menor a 44, por ende ponemos un uno:
128 64 32 16 8 4 2 1
   1  0  1  ?  ? ? ? ?   
 y volvemos a restar, 44-32 (esta es más fácil!), nos queda 12. Podemos completar los pesos de 8 y 4 con un 1, y el resto de los pesos con ceros:



128 64 32 16 8 4 2 1
 1  0  1  0  1 1 0 0

¿No es tan difícil, no? Ahora veamos cómo haríamos con números negativos. Me animaría a decir que es más fácil. El único cambio con el procedimiento que hicimos hasta ahora es que el peso de mayor significado es negativo, o sea:


-128 64 32 16 8 4 2 1

Obviamente también cambia el rango. Ahora será (-128;127). Deducir el rango a partir de recordar lo anterior (que el peso 128 es negativo) es bien fácil. Para el menor de los negativos (-128) ponemos un 1 en el único peso negativo:


-128 64 32 16 8 4 2 1
 1   0  0  0  0 0 0 0

y para el mayor de los positivos (127) ponemos unos en todos los pesos positivos:


-128 64 32 16 8 4 2 1
 0   1  1  1  1 1 1 1

Ahora el procedimiento para representar un negativo sería así:
1. Verificar que entre en el rango representable. En 8 bits dijimos es -128;127.
2. Colocar un 1 en el único peso negativo (-128)
3. Agregar un 1 en los pesos positivos necesarios para llegar al número objetivo, siguiendo el mismo mecanismo que con los positivos. Veámoslo con un ejemplo, supongamos el número -37.
Ponemos un 1 en el peso negativo:

-128 64 32 16 8 4 2 1
 1   ?  ?  ?  ? ? ? ?

Tenemos el -128 y queremos llegar a -37. Cada uno que completemos suma al -128 y nos acerca al objetivo. Oh casualidad que al sumar 64 a -128 nos da.... -64. Volvemos a sumar 32 a -64 y nos da -32. ¡Momento que soy lento! Nos pasamos. Queríamos el -37 y llegamos a -32. Así que en 32 va un cero:



-128 64 32 16 8 4 2 1
 1   1  0  ?  ? ? ? ?

Vamos en -64, nos dimos cuenta que no podemos sumarle 32 porque es demasiado. Pero sí sumamos 16, entonces nos queda -48 (esta es la parte difícil, sumar/restar mentalmente):


-128 64 32 16 8 4 2 1
 1   1  0  1  ? ? ? ?

Al -48 le sumamos 8 y nos queda -40:



-128 64 32 16 8 4 2 1
 1   1  0  1  1 ? ? ?

Si le sumamos 4 llegamos a -36... nuevamente es demasiado. Así que en el peso 4 va un cero:



-128 64 32 16 8 4 2 1
 1   1  0  1  1 0 ? ?

Teníamos -40, si ponemos un 1 en los últimos dos pesos (2 y 1) le sumamos 3, y llegamos a -37:



-128 64 32 16 8 4 2 1
 1   1  0  1  1 0 1 1

Objetivo alcanzado! La primera vez puede que se complique, pero luego de un poco de práctica se hace más natural. ¿Probaste hacerlo?


Edit (9/9/16): Tenia un error (arrastrado como vibora) que corregí gracias a la aguda observación de un alumno.
Edit (12/12/16): Otro error más! Por canchero. Corregido gracias a Maximiliano.