Números dentro del hardware de la computadora

Comprender conceptos matemáticos como el cambio de base de los números, las funciones exponenciales y logarítmicas, entre otros, te permitirá tener una comprensión más profunda de algoritmos y estructuras de datos utilizados en programación. Además, estos conceptos pueden ser útiles en la resolución de problemas matemáticos relacionados con la programación, como la optimización de algoritmos y la evaluación de la complejidad computacional.

Asimismo, el conocimiento de conceptos matemáticos puede ayudarte a entender y diseñar algoritmos para solucionar problemas más complejos, por ejemplo, en áreas como la inteligencia artificial, el aprendizaje automático y la criptografía.

Por lo tanto, aunque no sea necesario comprender estos conceptos para ciertas actividades específicas en programación, tener un conocimiento sólido de matemáticas y sus aplicaciones en programación puede ayudarte a ser un mejor desarrollador y a tener un conjunto más amplio de habilidades que te permitan resolver problemas de manera más efectiva y eficiente.

En este post veremos como se representan los números en las computadoras y la forma de calcular el error. Esto nos será de utilidad más adelante en el desarrollo de métodos numéricos y en el uso estructuras de datos.

Nociones previas


Sistema de números.

Cómo ya es sabido, podemos agrupar los números en conjuntos de modo que unos sean subconjuntos de otros. Veamos un ejemplo:

El conjunto de números naturales es:

N = {1, 2, 3, 4, 5, …}

El conjunto de los números enteros es:

Z = {…, --5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, …}

Si observamos detenidamente en el conjunto de los números enteros “Z”, a partir del 0 a la derecha, encontramos todos los números naturales. Por lo tanto, los números naturales son un subconjunto de los números enteros, o en simbología matemática “N” ⊂ “Z”. 

Ahora veamos todos lo conjuntos de números

Naturales: N = {1, 2, 3, 4, 5, …}

Enteros: Z = {…, --5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, …}

Racionales: Q = {…, -5, -4.999, -4.99801, -4.998009, …, 0, 0.001, …}  (son números decimales que pueden ser expresados en una fracción, es decir por más larga que sea la parte decimal siempre habrá un tope. Las únicas excepciones a esta regla, son los decimales periódicos puros y mixtos, que también son considerados racionales, ya que pueden ser expresados en fracción)

Irracionales: I = { e,π,√2, …} (son números decimales que no pueden ser expresados en fracción, debido a que su parte decimal es infinita y no periódica)

Reales: R = { Todos los anteriores juntos}

Complejos: C = { Todos los reales, los números imaginarios y la combinación de ambos} (Un número complejo tiene la forma: a + bi, donde “a” y “b” son números reales y la letra “i”, que multiplica a “b”,
es el número imaginario que equivale a √-1. En otras palabras, un número complejo está compuesto de una parte entera “a” y una parte imaginaria “bi”.

Notación científica

Para representar números en notación científica, es necesario ajustar el número para que su parte entera tenga una sola cifra diferente de 0. Para lograr esto, se debe multiplicar y dividir por potencias de diez de manera conveniente, sin modificar el valor del número original.

A continuación, se muestra un ejemplo práctico: para expresar el número 14789 en notación científica podemos escribirlo como 14789.0, de modo que ubiquemos la coma, y luego dividirlo entre 10000, para obtener una parte entera igual a 1. Finalmente, se debe multiplicar el resultado por 10000 para mantener el valor original del número.

Veamos otro ejemplo:

1547.4647 × 104 a notación científica

Solución:

Este número ya tiene una potencia de 10. Sin embargo, aún no tiene la forma adecuada. Dividimos entre 1000 y multiplicamos por 1000 para no alterar el valor.



Notación científica en el sistema binario

Un número se puede representar en notación científica para bases diferentes de 2 y 10. No obstante, para este punto nos enfocaremos en cómo se expresa un número binario en notación científica. Tomando como ejemplo el número 14789, lo primero que debemos hacer es expresarlo en sistema binario.

14 789 = (11100111000101)2

De manera similar a los ejemplos anteriores, debemos dividir entre potencias de dos y multiplicar por potencias de dos, de tal manera que el número original no se altere.

Otra forma alternativa de comprender este procedimiento es considerar que se utiliza un truco simple: al multiplicar por 213y dividir por la misma cantidad, el número original no se ve afectado, ya que se está aplicando una operación matemática de identidad 213/213 = 1.

Con la intención de fortalecer está noción, procederemos a expresar el número 20189.478 en notación científica en el sistema binario. Para hacerlo, el primer paso será convertir este número en su equivalente en binario, luego multiplicar y dividir por potencias de dos sin alterar el número.

20189.375 = (100111011011101.011)2

Cambio de base:

Los números se expresan en un sistema determinado mediante su subíndice final, y los números sin subíndice se asumen en el sistema decimal por defecto. Es posible representar un número en una base diferente y conservar su valor original. Aunque este concepto puede resultar familiar, es importante tenerlo en cuenta para evitar caer en la trampa de pensar que algunos números no lo cumplen. Por ejemplo, la fracción 1/10 se encuentra en el sistema decimal y, al ser comúnmente utilizado, no se indica su base. Sin embargo, al convertirla al sistema binario, se obtiene (0.0 0011 0011 0011 0011 …)2, donde se ha separado los decimales para destacar la periodicidad en el decimal infinito.

A simple vista, podría parecer que el número en el sistema binario no debería ser igual a su equivalente en el sistema decimal debido a su infinita cantidad de decimales. Sin embargo, como se mencionó anteriormente, eso no es cierto.

Ejemplos de números expresados en una cierta base:

    (10001)2
    (456712)10 = 456712
    (12102)3
    (713457)8

Para cambiar un número de base 10 a otra base diferente, se debe dividir el número original entre el valor de la base a la que se dese cambiar, luego el cociente y así sucesivamente.

Ejemplos:

  • (8945)10 a base 2

 (Haz clic en las imágenes si no son muy claras)

       Luego de realizar las divisiones sucesivas hasta ya no poder continuar, el número 8945 estará                representado en base 2 colocando los resultados obtenidos, del último (en rojo) al primero. 

        (8945)10 = (10001011110001)2


  • (8945.375)10 a base 2

    La parte entera se puede calcular por el método anterior:

    (8945)10 = (10001011110001)

    Para convertir la parte fraccionaria (0.375) en binario, se debe seguir un proceso específico. Primero, se multiplica sucesivamente por 2 y se observa si el resultado es menor que 1. Si es así, se representa esta operación con 0. Si es mayor o igual a 1, se representa con un 1. Cuando el resultado sea exactamente 1, se detienen las multiplicaciones y se obtiene el resultado final anotando los 0s y 1s en el orden que se obtuvieron.

                0.375 x 2 = 0.750 < 1           0
                0.750 x 2 = 1.5      1        →   1
                0.5     x 2 = 1, se detiene       1

        Como calculamos un número fraccionario, se agrega “0.” antes de los bits obtenidos de                la         siguiente forma: (0.011)2

        Por último, la parte entera y fraccionaria en binario se suman para obtener el valor final.                          (8945.375)10 = (10001011110001)2 + (011)2 = (10001011110001.011)2

Si deseamos convertir un número que se encuentra en una base distinta a la base diez a base diez, podemos utilizar la descomposición polinómica.

Ejemplo:

(10110111)2 a base 10

Solución:

Se separan los dígitos y cada uno se multiplica por una potencia de dos que aumenta consecutivamente de derecha a izquierda.

Entonces

(10110111)2 = (183)10

Para números con parte fraccionaria, se realiza el mismo proceso, pero disminuyendo el valor del exponente hacia la derecha. En otras palabras, se multiplica por la inversa de las potencias de 2.

Ejemplo:

(1011.1101)2 a base 10

Solución:
La parte entera (antes del punto) se encuentra en azul y la parte fraccionaria (después del  punto) se encuentra en rojo.

Entonces

    (1011.1101)2 = (11.8125)10


Representación de los números dentro del hardware de la computadora

Probablemente has leído o escuchado que en lenguaje de máquina se utilizan unos y ceros, también conocidos como bits. Esto es cierto, y es necesario convertir los números del sistema decimal al sistema binario para poder almacenarlos y trabajar con ellos en la computadora.

Un bit es la abreviatura de “dígito binario” y representa un elemento en memoria que puede estar encendido o apagado. Al igual que un interruptor, un bit puede ser representado como 1 si está encendido o como 0 si está apagado. Un conjunto de 8 bits se llama byte. (Nakamura, 1992)

Actualmente, la mayoría de las computadoras usan arquitecturas de 64 bits, pero algunos dispositivos pueden trabajar con arquitecturas de 32 bits, como es el caso de Raspberry Pi.

Para almacenar números enteros en una computadora con arquitectura de 32 bits, se utiliza el primer bit para representar el signo del número: positivo si es 0, negativo si es 1. Los 31 bits restantes se utilizan para almacenar el número en sistema binario.

Es importante mencionar que el autor Nakamura, en su libro “Métodos numéricos aplicados con Software”, sigue los mismos pasos para distintas arquitecturas, incluyendo la de 16 bits. Sin embargo, esto se aplica al ejemplo tomado de 32 bits e igualmente para 64 bits.

Ejemplo:

Se desea almacenar el número 7843, por lo que lo convertimos a binario y, dado que es positivo, nuestro primer bit a la izquierda lo lema

(7843)10 = (1111010100011)2

Dado a que el número en cuestión es positivo, el primer bit lo en la tabla inferior se rellena con 0. Luego, se coloca el número binario en la mantisa y, debido a que tiene 13 dígitos, los 18 espacios sobrantes los rellenamos con 0.

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

1

1

1

1

0

1

0

1

0

0

0

1

1


Límites de la precisión simple

Tomando como punto de partida el ejemplo anterior, surge la pregunta de qué sucedería si en lugar de rellenar los espacios de la mantisa con ceros y unos, se utilizara solo el valor de 1 para completarlos. Es decir, ¿qué ocurriría si se representara el número utilizando la máxima cantidad de bits de en la mantisa y estos tuvieran un valor de 1? Esta cuestión tiene una respuesta sencilla, pero tal vez poco intuitiva.

Veamos el planteamiento en una tabla llenando con unos toda la mantisa y asignando 0 al bit del signo.

0

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1


Cambiando de sistema la mantisa: (1111111111111111111111111111111)2 = (2147483647)10

Esto nos da el mayor número que se puede representar con 32 bits: 231-1 = (2147483647)10

Ahora bien, en el caso de asignar el valor 1 al bit del signo y aplicar el razonamiento anterior para la mantisa, se obtiene el menor número que se puede representar en 32 bits.

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1


Cambiando de sistema la mantisa: (1111111111111111111111111111111)2 = (2147483647)10

Al agregar el signo, el menor número que se puede representar es -(231-1) = -(2147483647)10

¿Cómo es posible que el mayor dígito sea (231-1)?

Aunque pueda parecer poco intuitivo, te invito a seguir el razonamiento que expondré a continuación. En este sistema de representación numérica que estamos considerando, se utilizan un total de 32 bits, de los cuales 31 se utilizan para expresar el número en sí y uno para el exponente. Los 31 bits pueden ser llenados con diferentes combinaciones de unos y ceros, dependiendo del número que se quiera almacenar en sistema binario. Como es de esperar, el mayor número que puede ser almacenado es aquel en el que todos los bits son iguales a 1.

Cabe destacar que, en el sistema binario, cuando se suma un 1 al número completo, se lleva 1 para la siguiente posición de los dígitos. Por ejemplo:

(1000)2 + (1)2 = (1001)2
(1001)2 + (1)2 = (1010)2
(1010)2 + (1)2 = (1011)2
(1011)2 + (1)2 = (1100)2
(1100)2 + (1)2 = (1101)2
(1101)2 + (1)2 = (1110)2
(1110)2 + (1)2 = (1111)2
(1111)2 + (1)2 = (10000)2
(10000)2 + (1)2 = (10001)2

Según este patrón, si a nuestro número máximo (1111111111111111111111111111111)2 le sumamos (1)2, se obtendría (10000000000000000000000000000000)2, un 1 acompañado de 31 veces 0. Si usamos la descomposición polinómica para convertirlo a sistema decimal se obtiene 231, lo que es igual a nuestro número máximo más (1)2. Por lo que, si queremos volver al número máximo, debemos operar 231-(1)2, y dado que (1)2 = (1)10 (Anexo A), el número máximo que podemos guardar en 32 bits es 231-1.

Si todavía no está claro este punto, se recomienda repasarlo varias veces, ya que lo que se explicará a continuación será más fácil de seguir, pero requerirá de estas herramientas previas y, a pesar de que este planteamiento es correcto, las máquinas utilizan una representación más didáctica llamada “complemento a dos” para almacenar números negativos. (Nakamura, 1992)

Representación en punto flotante

Los números reales se representan por medio de los formatos de punto flotante. Hay cinco formatos básicos definidos: tres formatos binarios, con codificación en longitudes de 32, 64 y 128 bits y dos formatos decimales, con codificación en longitudes de 64 y 128 bits. (Engineers, 2008)

Los formatos binarios, son los más usados por hardware y lenguajes de programación. Estos brindan una representación en punto flotante para los números reales bajo la definición del estándar IEEE 754 (Institute of Electrical and Electronic Engineers).

Hay dos tipos de precisión según el número de bits utilizados para almacenar al número en punto flotante: precisión simple para 32 bits y precisión doble para 64 bits.

Para la representación en punto flotante, se debe expresar el número en el sistema binario, y luego en notación científica normalizada y finalmente ubicar el número en los bits a disposición. Veamos el ejemplo de almacenar el número 1002144.12 en precisión simple.

Paso 1: Convertir a binario

    1002144.12 = (11110100101010100000.011)2

Paso2: Convertir a notación científica normalizada

La notación científica normalizada, en síntesis, es la notación científica que se ha visto en la sección de nociones básicas al inicio del texto, con la pequeña diferencia de que la parte entera debe ser 0, obligatoriamente.


Paso 3: Almacenar el número obtenido bajo el estándar IEEE 754 para precisión simple.

De acuerdo al estándar, los 32 bits (4 bytes) se separan en tres partes: 1 bit para el signo, 8 bits para el exponente y 23 bits para la mantisa.




Comentarios

Entradas populares de este blog

Instalación del IDE Eclipse para Java y JShell

POO (Programación Orientada a Objetos), public, private y clases en Java - 1

Instalación de java y manejo de versiones