SISTEMAS DE NUMERACIÓN
Sistema decimal

Desde antiguo el Hombre ha ideado sistemas para numerar objetos, algunos sistemas primitivos han llegado hasta nuestros días, tal es el caso de los "números romanos", pero sin duda el más extendido en la actualidad es el sistema decimal de números arábigos, llamado así por ser los árabes sus creadores.

En el sistema decimal, los números se forman por combinación de 10 signos distintos; 0, 1, 2, 3, 4, 5, 6, 7, 8 y 9. Cada uno de estos signos tiene un valor, y el valor del número que forman se halla multiplicando el valor de cada uno de ellos por 10 elevado a la potencia correspondiente a su situación en el número, siendo 0 el de más a la derecha, 1 el siguiente y así sucesivamente. De esta forma, el número 5348 sería igual a:

5348 = 8*100 + 4*101 + 3*102 + 5*103
= 8*1 + 4*10 + 3*100 + 5*1000

La misma denominación del número nos lo recuerda, decimos: cinco mil, tres cientos, cuarenta y ocho. El sistema decimal es de uso tan frecuente que no vale la pena insistir en él, pero es importante hacer notar que la base de los exponentes es siempre 10 y por tanto, este sistema se denomina también "de base 10". Es posible crear sistemas que utilicen una base distinta, y de hecho, estos sistemas son muy usados en informática.

Sistema binario

Un ordenador es una máquina esencialmente binaria, su componente básico es el transistor, que sólo admite dos estados posibles, o bien pasa corriente, o bien no pasa.

Los "puristas" podrían objetar que un transistor puede tener múltiples estados dependiendo de la cantidad de corriente que pase; es cierto, pero la medición de esta cantidad de corriente implica una imprecisión que podría crear ambigüedades, y un ordenador no admite ambigüedad. De forma que por debajo de un determinado valor, se considera que no pasa corriente, y por encima de otro, se considera que sí pasa.

Arbitrariamente, asociamos estos dos estados con dos dígitos, cuando no pasa corriente decimos que tenemos un "0" y cuando pasa, decimos que tenemos un "1". De esta forma, podremos representar el estado de un interruptor: "1" cuando esté encendido y "0" cuando esté apagado.

Si tenemos una serie de interruptores puestos en fila, podríamos representar el estado de todos ellos mediante un número binario. En la FIGURA 1 vemos una serie de interruptores cuyo estado podría ser definido mediante el número binario: "10011".

[Figura 1]

Como se ve, el sistema binario es perfectamente adecuado para su uso en circuitos electrónicos. A cada "1" o "0" de un número binario le llamaremos "dígito binario", que puede abreviarse como "bit" (contracción de "binary digit").

El valor de un número binario se halla de la misma forma que en el sistema decimal, excepto que esta vez, la base es "2". Así el número "10011" será:

10011 = 1*20 + 1*21 + 0*22 + 0*23 + 1*24

Es decir:

10011 = 1*1 + 1*2 + 0*4 + 0*8 + 1*16 = 19 en decimal

Ya hemos visto implícitamente, cómo transformar un número binario en decimal, el proceso inverso (transformar un número decimal en binario), lo veremos más adelante, cuando estudiemos el método general para transformar números en cualquier base.

Operaciones aritméticas en binario

Los números binarios se pueden sumar, restar, multiplicar y dividir de igual forma que los decimales, sólo es necesario conocer las "tablas" correspondientes. Veamos primero la suma.

Para sumar en decimal los números 19 y 28, los colocamos de la siguiente forma:


+
19
28

Y a continuación hacemos: "9 más 8 igual 7 y me llevo 1, 1 más 1 más 2 igual 4" el resultado es 47, es decir:



+
1
19
28
=
47

Al sumar 9 y 8 nos da un resultado superior a 9, es decir, superior al dígito más alto de nuestro sistema, por lo que decimos que "nos llevamos una", esta "una" que "nos llevamos" se denomina en binario "acarreo" (o "carry" en inglés). Cuando se suma en binario, es necesario tener en cuenta el acarreo.

Vamos ahora a ver la "tabla de sumar" en binario:

0 + 0 = 0
0 + 1 = 1
1 + 1 = 10

Es decir, cuando sumamos 1 más 1 el resultado es 0 pero se produce un acarreo de 1. Veamos un ejemplo: vamos a sumar los números 19 y 28 en binario, 19 es 10011 y 28 es 11100, de esta forma:



+
1
010011
011100
=
101111

El resultado es 101111, o bien 47 en decimal. Al sumar los dos unos de la izquierda, se ha producido un acarreo que hemos anotado encima de la siguiente columna. Al igual que en decimal, los ceros a la izquierda son irrelevantes.

Es interesante saber cómo realiza el ordenador esta operación. El programador de Basic, seguramente, esté familiarizado con los operadores lógicos AND, OR y NOT, pero quizá no lo esté tanto con el operador EXOR (OR exclusivo). A continuación se muestran las "tablas de verdad" correspondientes a estos operandos. Es conveniente manejar con facilidad el operador EXOR, ya que se utiliza con frecuencia al programar en código máquina.

0 AND 0 = 0
0 AND 1 = 0
1 AND 0 = 0
1 AND 1 = 1

0 OR 0 = 0
0 OR 1 = 1
1 OR 0 = 1
1 OR 1 = 1

NOT 0 = 1
NOT 1 = 0

0 EXOR 0 = 0
0 EXOR 1 = 1
1 EXOR 0 = 1
1 EXOR 1 = 0

El equivalente eléctrico del operador AND, serían dos interruptores en serie, el del operador OR, dos interruptores en paralelo. Siguiendo la misma analogía, el equivalente eléctrico del operador EXOR, serían dos interruptores conmutados, como los que se utilizan frecuentemente para encender y apagar la luz de una habitación desde dos puntos distintos.

Vistas estas tablas, no es dificil deducir la correspondencia con la tabla de sumar vista anteriormente. La suma se obtiene mediante una operación EXOR entre los dos bits, y el acarreo se obtiene mediante una operación AND. Esta correspondencia es la que permite a un ordenador realizar cálculos, ya que eléctricamente, sólo es posible realizar operaciones lógicas.

No obstante, no se preocupe el lector por tener que realizar operaciones lógicas bit a bit cada vez que quiera sumar dos números, el juego de instrucciones del microprocesador Z-80, afortunadamente, incluye las instrucciones necesarias para realizar sumas y restas de forma bastante sencilla.

Números negativos

Hemos visto cómo suma un ordenador, pero ¿cómo resta? Para conseguir restar en binario, tendremos que establecer antes un convenio sobre qué consideramos números negativos.

Se denomina "complemento a 1" de un bit a lo que le falta a ese bit para ser "1", es decir, el complemento de "1" es "0" y el de "0" es "1" (el complemento a 1 viene dado por el operador lógico NOT). Por tanto, el complemento a 1 de un número binario es el resultado de cambiar sus "unos" por "ceros" y sus "ceros" por "unos". Por ejemplo: el complemento a 1 de "10011101" es "01100010".

Por otro lado, se denomina "complemento a 2" al "complemento a 1" más 1, es decir, al resultado de cambiar los unos por ceros y los ceros por unos, y luego sumar uno. Veamos algunos ejemplos:

[Figura 1]

Podría parecer algo arbitrario, sin embargo es súmamente útil, ya que como veremos a continuación, es posible usar el complemento a 2 de un número como su negativo. Para restar dos números, sumamos al "minuendo" el complemento a 2 del "sustraendo". Vamos a ver algunos ejemplos, trabajando con números de 8 bits, que son los que utiliza el Z-80 (de hecho, también utiliza números de 16 bits, pero sería demasiado largo para un simple ejemplo). Vamos a restar 28 menos 19, para lo cual sumamos a 28 el complemento a 2 de 19:


-
28
19
=
9

+
00011100
11101101
=
100001001

Obtenemos el número "00001001" con un acarreo de "1". El acarreo nos indica que el resultado es positivo, es decir, el resultado es "+9" como cabía esperar.

Ahora vamos a realizar la operación inversa, es decir, vamos a restar 19 menos 28 por tanto, tendremos que sumar a 19 el complemento a 2 de 28:


-
19
28
=
-9

+
00010011
11100100
=
011110111

Esta vez hemos obtenido el número "11110111" con un acarreo de "0". El hecho de que el acarreo sea "0" nos indica que el número es negativo, y "11110111" es, precisamente, complemento a 2 de "9", es decir, "-9" como también cabía esperar.

Un hábil lector habrá comprobado que, trabajando con números de 8 bits, podemos saber si un número es negativo con sólo mirar el primer bit (el de más a la izquierda); si este bit es "1", el número será negativo. Bien, esto no siempre es cierto. Trabajando con 8 bits, se pueden representar 256 números distintos (desde 0 hasta 255), el Z-80 los considera casi siempre, todos positivos, pero hay veces que considera positivos a los 128 primeros (desde 0 a 127) y negativos a los 128 restantes (desde 128 a 255). En este último caso, sí funciona la regla explicada anteriormente, y de hecho, al bit de más a la izquierda se le denomina "bit de signo".

De esta forma, 255 sería equivalente a "-1", 254 a "-2", 253 a "-3", y así sucesivamente hasta 128 que sería en realidad, "-128". Podría parecer un poco "lioso", pero con un poco de imaginación, se puede asimilar al funcionamiento de un cuenta-kilómetros de automóvil. Si partimos de un número cualquiera y vamos restando 1, llegará un momento que obtendremos "00000000", si a continuación volvemos a restar 1, obtendremos "11111111"(más un acarreo, lógicamente), es decir, "255" en decimal, si volvemos a restar 1, obtendremos "254"; parece lógico asignar a "255" el valor "-1" y a "254" el "-2" y así sucesivamente. En la segunda columna de la FIGURA 2, podrá ilustrar esto con mayor claridad.

[Figura 2A] [Figura 2B] [Figura 2C]
[Figura 2D] [Figura 2E] [Figura 2F]
[Figura 2G] [Figura 2H]
Sistema hexadecimal

Como hemos visto, los números binarios son muy adecuados para su uso en aparatos electrónicos, pero tienen un gran inconveniente; cuando los escribimos, necesitamos una gran cantidad de cifras para representar un número relativamente pequeño. Si pudiéramos agrupar los bits, conseguiríamos evitar este inconveniente.

Dado que vamos a trabajar con 8 o 16 bits, parece lógico agruparlos de 4 en 4 con el fin de obtener números de 2 o 4 cifras. Como regla general, con "n" bits se pueden obtener "2 elevado a n" combinaciones distintas, por tanto, con 4 bits podemos obtener 16 combinaciones, cada una de las cuales las asociaremos con un dígito hexadecimal.

Necesitamos 16 dígitos para representar todas las posibles combinaciones, como sólo conocemos 10 dígitos distintos (del 0 al 9), utilizaremos las 6 primeras letras mayúsculas del abecedario (de la "A" a la "F"). En la FIGURA 3 se pueden ver las 16 combinaciones posibles con 4 bits y su equivalente en hexadecimal.

[Figura 3]

Supongamos el número binario "01101100", siguiendo la tabla de la FIGURA 3, podemos escribirlo como "6Ch". Hemos esxrito "6" en lugar de "0110" y "C" en lugar de "1100", la "h" se añade al final para indicar que se trata de un número hexadecimal y no confundirlo con uno decimal. A los números hexadecimales se les denomina con frecuencia, simplemente, "Hexa".

La forma de tranformar un número Hexa en decimal, es sumamente sencilla, basta con multiplicar el valor de cada dígito por 16 elevado a la correspondiente potencia (como hacíamos anteriormente para los binarios y decimales); habrá que tener en cuenta, que "A" vale 10, "B" vale 11, "C" vale 12, "D" vale 13, "E" vale 14 y "F" vale 15. Veamos algún ejemplo, vamos a convertir a decimal el número "5CB2h":

5CB2h = 2*160 + B*161 + C*162 + 5*163

es decir:

5CB2h = 2*1 + 11*16 + 12*256 + 5*4096 = 23730

El resultado es "23730" en decimal, precisamente la dirección de la variable del Sistema "RAMTOP". Las direcciones de memoria en el Spectrum son siempre números Hexa de 4 cifras, la razón es que existen 65536 direcciones posibles, que es el número de combinaciones que se pueden hacer con 16 bits, es decir, cuatro cifras hexadecimales.

Si contempla un mapa de memoria del Spectrum, las direcciones que definen el inicio de las distintas zonas pueden parecer algo arbitrarias; pero estos números vistos en Hexa, resultan ser "números redondos"; vamos a comprobarlo: 16384 (el principio de la RAM) es 4000h en Hexa, 65535 (el final de la RAM) es FFFFh, 1024 (1K) es 0400h, 16K es 4000h, 32K es 8000h, 48K es C000h y finalmente, 64K es 10000h. El archivo de pantalla ocupa desde 4000h hasta 5800h, el de atributos desde 5800h hasta 5B00h, el buffer de impresora va desde 5B00h hasta 5C00h, la pantalla ocupa 1800h bytes, los atributos 300h bytes y el buffer de impresora 100h bytes.

Esto quiere decir que si hemos de trabajar directamente sobre la memoria, es preferible que nos vayamos acostumbrando a contar en hexadecimal.

Conversión entre bases

Hasta ahora hemos visto cómo pasar números desde cualquier base a decimal; ahora vamos a estudiar el proceso inverso, pasar números de base decimal a cualquier base.

Este proceso es algo tedioso para realizarlo "a mano", así que normalmente usaremos un programa de ordenador, de hecho, la mayoría de ensambladores tienen una opción que nos permite pasar números a hexadecimal, y si aún no tiene un ensamblador, puede utilizar el PROGRAMA 1 para pasar números a y desde cualquier base.

[Programa 1]

No obstante, es necesario saber cómo se realiza el proceso, entre otras cosas, para ser capaz de escribir un programa que lo haga. Como regla general, para pasar un número de base decimal a cualquier base, se divide el número por la base sin sacar decimales, el resto es el primer dígito de nuestro número (empezando por la derecha). A continuación se vuelve a dividir el cociente, y se toma el nuevo resto como el siguiente número, y así sucesivamente hasta que obtengamos en cociente de cero. Recuerde que no debe sacar decimales.

En la FIGURA 4 hemos realizado el proceso para pasar el número 23730 a Hexa, y en la FIGURA 5 hemos pasado el mismo número a binario.

[Figura 4]
[Figura 5]

Como regla general, a partir de ahora representaremos los números hexadecimales seguidos de una "h" y los binarios, seguidos de una "b".

Con el PROGRAMA 1, podrá introducir un número en decimal, binario o Hexa, y el programa devolverá como resultado, ese mismo número en decimal, Hexa y binario. Cuando introduzca un número binario, indíquelo terminando el número con una "b" minúscula, si introduce un número hexadecimal, termínelo con una "h" también minúscula, los números decimales deberá teclearlos tal cual. Por último, no olvide que las cifras que componen un número hexadecimal, deben ser números o letras mayúsculas entre la "A" y la "F". En aras de una mayor rapidez de ejecución, el programa no está protegido contra entradas erróneas. Los números no deben ser mayores de 65535 (FFFFh o 1111111111111111b).

[Ejercicios]