Articles

Valor máximo de un entero: Java Vs C vs Python

Introducción

En Ciencia de Datos, cuando hablamos de enteros, nos referimos a un tipo de datos que representa algún rango de enteros matemáticos. Sabemos que los enteros matemáticos no tienen un límite superior, pero esto podría ser un problema en cuanto al tamaño de la memoria, obligando a casi todas las arquitecturas de ordenadores a limitar este tipo de datos.

Así que esa es la pregunta que intentamos hacer hoy: «¿Cuál es el máximo valor entero que podemos representar en una determinada máquina?»

Explicación del problema

Bueno, no hay una respuesta única a esta pregunta ya que hay muchos factores que influyen en la respuesta. Los principales son:

  • Bits de plataforma
  • Lenguaje utilizado
  • Versiones con o sin signo
    • En informática, la representación más común de los enteros es mediante un grupo de dígitos binarios (bits), almacenados como un sistema numérico binario. El orden de los bytes de memoria varía – con n bits, podemos codificar 2^n enteros.

      Podemos ver las diferencias en este sencillo ejemplo: con n bits, podemos codificar enteros desde 0 hasta 2^n - 1 o desde - 2^{n-1} hasta 2^{n-1} - 1.

      Por lo general, el tamaño de los enteros n está definido por la arquitectura de la máquina, pero algunos lenguajes informáticos también definen los tamaños de los enteros de forma independiente. Diferentes CPUs soportan diferentes tipos de datos, basados en su propia plataforma. Normalmente, todas soportan tipos con y sin signo, pero sólo de un conjunto limitado y fijo de anchos, normalmente de 8, 16, 32 y 64 bits.

      Algunos lenguajes definen dos o más tipos de datos enteros, uno más pequeño para preservar la memoria y ocupar menos almacenamiento, y otro más grande para mejorar el rango soportado.

      Otra cosa a tener en cuenta es el Tamaño de Palabra (también llamado Longitud de Palabra) de la plataforma.

      En informática, una palabra es la unidad de datos utilizada por un diseño de procesador concreto, un trozo de datos de tamaño fijo manejado como una unidad por el hardware del procesador. Cuando hablamos del tamaño de la palabra, nos referimos al número de bits que hay en una palabra y ésta es una característica crucial de cualquier arquitectura de ordenador y diseño de procesador específicos.

      Las arquitecturas actuales suelen tener un tamaño de palabra de 64 bits, pero también las hay con 32 bits.

      Hora de las respuestas

      En esta sección, responderemos a nuestras preguntas empezando por el viejo amigo C hasta el relativamente nuevo Python, pasando por el sempiterno Java. Empecemos.

      3.1. C

      El lenguaje C fue diseñado en 1972, con el propósito de funcionar de la misma manera en diferentes tipos de máquinas. Así, no determina directamente un rango para el tipo de datos entero, ya que eso depende de la arquitectura de la máquina.

      Sin embargo, C tiene dos tipos de enteros; cortos y largos.

      Un entero corto es, como mínimo, de 16 bits. Por tanto, en una máquina de 16 bits, coincide con el formato de entero largo. El formato de entero corto va de -32.767 a 32.767 para la versión con signo y de 0 a 65.535 para la sin signo. Es raro, pero parece que para la versión con signo nos falta un número. Eso es fácil de explicar: ¡porque necesitamos un bit para el signo!

      Si corremos en un sistema de 64 bits, podemos calcular fácilmente que el formato largo puede alcanzar un valor 2^{64-1}, que corresponde a 18,446,744,073,709,551,615 para el tipo de datos sin signo y oscila entre -9,223,372,036,854,775,807 y 9,223,372,036,854,775,807 en la versión con signo.

      Para completar, daremos un pequeño paseo por el tipo de datos entero largo. El formato long long no está disponible en C, sino sólo en la versión C99. Tiene el doble de capacidad de memoria que un tipo de datos long, pero obviamente no está soportado por los compiladores que requieren el estándar anterior de C. Con el tipo de datos long, podemos llegar a un enorme 2^{64-1} si lo ejecutamos en una máquina de 32 bits o superior.

      3.2. Java

      Hablando de Java, debemos recordar que funciona a través de una máquina virtual. Eso nos ahorra toda la variabilidad explicada para el lenguaje C.

      Java sólo soporta versiones con signo de los enteros. Son:

      • Byte (8 bits)
      • Corto (16 bits)
      • Int (32 bits)
      • Long (64 bits)
      • Así, con el formato de entero largo podemos llegar a 2^{64-1} como con C en una máquina de 64 bits pero, esta vez, en cada arquitectura de máquina.

        Sin embargo, con alguna manipulación de bits, podemos obtener versiones sin signo, gracias al formato char. Ese es un formato de 16 bits, por lo que el formato de entero sin signo puede llegar a 65.535.

        Pero con Java, podemos ir más allá con un pequeño hack para poder representar números enteros muy grandes a través de la librería de clases BigInteger. Esta biblioteca combina matrices de variables más pequeñas para construir números enormes. El único límite es la memoria física, por lo que podemos representar un rango enorme, pero aún limitado, de números enteros.

        Por ejemplo, con 1 kilobyte de memoria, podemos alcanzar enteros de hasta 2.466 dígitos de longitud!

        3.3. Python

        Python soporta directamente los enteros de precisión arbitraria, también llamados enteros de precisión infinita o bignums, como construcción de primer nivel.

        Esto significa que, al igual que con Java BigInteger, utilizamos tanta memoria como sea necesaria para un entero arbitrariamente grande. Así que, en términos de lenguaje de programación, esta cuestión no se aplica en absoluto a Python, porque el tipo de entero simple es, teóricamente, ilimitado.

        Lo que no es ilimitado es el tamaño de palabra del intérprete actual, que es el mismo que el tamaño de palabra de la máquina en la mayoría de los casos. Esa información está disponible en Python como sys.maxsize, y es el tamaño de la lista o secuencia en memoria más grande posible, que corresponde al valor máximo representable por una palabra con signo.

        En una máquina de 64 bits, corresponde a 2^{64-1} = 9.223.372.036.854.775.807.

        Diagrama de flujo

        Veamos un diagrama de flujo para resumir lo que hemos visto hasta ahora:

        Código real para cada lenguaje

        Aquí hay un código real para comprobar directamente lo que hemos visto hasta ahora. El código demostrará los valores máximos y mínimos de los enteros en cada lenguaje.

        Como esos valores no existen en Python, el código muestra cómo mostrar el tamaño de palabra del intérprete actual.

        5.1. Código C

#include<bits/stdc++.h>int main() { printf("%d\n", INT_MAX); printf("%d", INT_MIN); return 0; }

5.2. Código Java

public class Test { public static void main(String args) { System.out.println(Integer.MIN_VALUE); System.out.println(Integer.MAX_VALUE); }}

5.3. Código Python

import platformplatform.architecture()import syssys.maxsize

Conclusión

En este artículo, hemos cubierto las diferencias entre estos tres lenguajes principales sobre el máximo número entero posible. También mostramos cómo esta cuestión no se aplica en algunas situaciones.

Sin embargo, uno siempre debe utilizar el que mejor se ajuste a su situación para evitar el consumo de memoria y el retraso del sistema.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *