Volver a la lista

Desbordamiento de enteros y limitaciones de punto flotante.

Comprenda los principios de por qué una computadora determina que 0.1 + 0.2 ≠ 0.3 y por qué ocurre el desbordamiento de enteros.

Intermedio
|
10min
|
Verificado (2026-07)
desbordamiento de enteroscoma flotanteIEEE 754pérdida de precisióncálculo numérico
Progreso0/23 (0%)

Desbordamiento de enteros y limitaciones de punto flotante

Al finalizar este tema

Comprenderá por qué ocurre el desbordamiento de enteros, podrá explicar las limitaciones de precisión del punto flotante y conocerá las precauciones necesarias al realizar comparaciones numéricas.


Las computadoras cometen errores con los números

python
print(0.1 + 0.2) # 0.30000000000000004
print(0.1 + 0.2 == 0.3) # False!

Esto no es un error de Python. Ocurre en C, Java, JavaScript, Rust y en todos los demás lenguajes. Se debe a la forma en que las computadoras almacenan los números de punto flotante.


Desbordamiento de enteros

Número de bits y rango

En las computadoras, los enteros se representan con un número fijo de bits.

text
Entero de 8 bits sin signo: 0 ~ 255
Entero de 8 bits con signo: -128 ~ 127
Entero de 32 bits con signo: -2.147.483.648 ~ 2.147.483.647
Entero de 64 bits con signo: -9,2 × 10^18 ~ 9,2 × 10^18

Al exceder el rango, se produce un desbordamiento.

Qué es el desbordamiento

En un entero sin signo de 8 bits, ¿cuánto es 255 + 1?

text
11111111  (255)
+ 00000001  (1)
----------
 100000000  (256, pero se descarta el noveno bit)
= 00000000  (0)

¡Después de 255, vuelve a 0! Esto es un desbordamiento. Es como el cuentakilómetros de un coche que pasa de 999.999 a 000.000.

Casos reales de errores

c
// C: desbordamiento de un entero de 32 bits
int balance = 2147483647;  // Valor máximo
balance = balance + 1;      // -2147483648: pasa de positivo a negativo
  • Explosión del cohete Ariane 5 (1996): Conversión de un valor de 64 bits a 16 bits → desbordamiento (overflow) → autodestrucción del cohete
  • Visualizaciones de YouTube de "Gangnam Style" (2014): Superación del límite de enteros de 32 bits (2.100 millones) → Google cambió a 64 bits

Python no tiene desbordamiento

python
# Python no limita el tamaño de los enteros
big = 2 ** 100
print(big) # 1267650600228229401496703205376
bigger = 2 ** 1000
print(len(str(bigger))) # Un número de 302 dígitos

Python expande la memoria automáticamente según sea necesario. Sin embargo, en la mayoría de los lenguajes, como C, Java y JavaScript, el tamaño de los enteros es fijo, por lo que se debe tener cuidado con el desbordamiento (overflow).

NumPy también puede presentar desbordamientos, ya que los arreglos de NumPy utilizan enteros de tamaño fijo al estilo de C:

python
import numpy as np
a = np.int32(2147483647)
print(a + 1) # -2147483648 (desbordamiento)
b = np.int64(2147483647)
print(b + 1) # 2147483648 (seguro con 64 bits)

Punto flotante — IEEE 754

Al convertir 0,1 a binario

Así como en el sistema decimal 1/3 = 0,333333... es un número decimal periódico, en el sistema binario 0,1 = 0,0001100110011... es un número binario periódico.

text
0,1 (decimal) = 0,00011001100110011001100110011... (binario, repetición infinita)

La computadora almacena este número decimal infinito utilizando un número finito de bits (64 bits), por lo que debe truncarlo en algún punto. Este truncamiento es la causa del error.

IEEE 754 — Punto flotante de 64 bits

text
[1 bit de signo][11 bits de exponente][52 bits de mantisa]
 0          01111111011  1001100110011001100110011001100110011001100110011010

Signo: 0 (positivo)
Exponente: determina el exponente real
Mantisa: cifras significativas (52 bits ≈ 15~17 dígitos de precisión)
python
# Precisión limitada a 15~17 dígitos
print(f"{0.1:.20f}") # 0.10000000000000000555
print(f"{0.2:.20f}") # 0.20000000000000001110
print(f"{0.3:.20f}") # 0.29999999999999998890

Dado que ni 0.1 ni 0.2 son precisos, el resultado de la suma tampoco lo es.


Problemas prácticos y soluciones

1. Comparación: no comparar con el == absoluto

python
# Bad
if 0.1 + 0.2 == 0.3:
print("Equal") # No se ejecuta
# Bien: usa una tolerancia epsilon
epsilon = 1e-9
if abs((0.1 + 0.2) - 0.3) < epsilon:
print("Equal") # Se ejecuta
# Mejor: usa math.isclose
import math
if math.isclose(0.1 + 0.2, 0.3):
print("Equal") # Se ejecuta

2. Error acumulado: aumenta en los cálculos iterativos

python
total = 0.0
for _ in range(1000):
total += 0.1
print(total) # 99.99999999999857 (no es 100)
print(f"Error: {abs(total - 100):.15f}") # 0.000000000001432

3. Cálculos financieros — Uso de Decimal

python
from decimal import Decimal
# float: se produce un error de precisión
price = 0.1 + 0.2
print(price) # 0.30000000000000004
# Decimal: exacto
price = Decimal('0.1') + Decimal('0.2')
print(price) # 0.3 (exacto)
# Atención: debe inicializarse con una cadena
Decimal(0.1) # Decimal('0.1000000000000000055511151231257827021181583404541015625')
Decimal('0.1') # Decimal('0.1'): exacto

Montos, impuestos, tasas de interés: en cálculos donde la precisión es crucial, se utiliza Decimal en lugar de float.


Números en JavaScript: enteros y punto flotante

JavaScript no tiene un tipo de dato entero. Todos los números son de punto flotante de 64 bits (IEEE 754).

javascript
// JavaScript: pérdida de precisión con enteros grandes
console.log(9007199254740992 === 9007199254740993);  // true!
// Considera iguales ambos números porque superan la mantisa de 52 bits

console.log(Number.MAX_SAFE_INTEGER);  // 9007199254740991 (2^53 - 1)

Por esta razón, se introdujo BigInt en JavaScript:

javascript
const big = 9007199254740993n;  // Literal BigInt con sufijo n
console.log(big === 9007199254740993n);  // true: exacto

Esta es también la razón por la que los IDs de los tuits de Twitter (actualmente X) se transmiten como cadenas de texto: si se analizan como números en JSON, se pierde la precisión, por lo que la API también proporciona el ID como una cadena "id_str".


Valores especiales

python
# Infinito
print(float('inf')) # inf
print(float('inf') + 1) # inf
print(float('inf') * -1) # -inf
# NaN (Not a Number)
print(float('nan')) # nan
print(float('nan') == float('nan')) # False: NaN ni siquiera es igual a sí mismo
import math
print(math.isnan(float('nan'))) # True: forma correcta de comprobarlo
print(math.isinf(float('inf'))) # True

NaN es el único valor que no es igual a sí mismo y cuyo == es False. Para verificar NaN, se debe usar siempre math.isnan().


Resumen clave

ConceptoResumen
Desbordamiento de enterosEl valor se invierte al superar el número fijo de bits. Python es una excepción (expansión automática)
IEEE 754Estándar de punto flotante de 64 bits. 52 bits de mantisa ≈ precisión de 15 a 17 dígitos
0.1 + 0.2 ≠ 0.30.1 es un decimal periódico en binario → se trunca al almacenar → genera error
ComparaciónUsar math.isclose() en lugar de ==
Cálculos financierosUsar Decimal en lugar de float
NaNUn valor que no es igual a sí mismo. Verificar con math.isnan()

La idea de que "las computadoras realizan cálculos con precisión exacta" es un error. Dado que las computadoras representan números infinitos con un número finito de bits, tienen límites inherentes de precisión. Comprender estos límites aclara por qué se usa Decimal en sistemas financieros, por qué las coordenadas en los juegos "tiemblan" y por qué es necesario el análisis de errores en cálculos científicos.

Reglas prácticas: Los enteros son seguros en Python; en otros lenguajes, verificar el rango. Para decimales, está estrictamente prohibido usar ==; para finanzas, usar Decimal. Verificar NaN con math.isnan().


💬 Preguntas y comentarios

0 comentarios

Puedes publicar sin iniciar sesión. Los comentarios de invitados no pueden editarse ni eliminarse después.

0/2000

Cargando...