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
-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.