Manejo de números en Dart: de enteros a precisión arbitraria
Los números en Dart se dividen en tres categorías principales según su naturaleza: int para enteros, double para decimales y num como un supertipo que puede ser cualquiera de los dos. Si necesitas precisión absoluta para valores astronómicos que exceden los límites de un entero de 64 bits, debes recurrir a BigInt.
La lógica de esta separación busca optimizar el rendimiento y la semántica: los int están diseñados para conteos e índices, mientras que los double siguen el estándar IEEE 754 para mediciones y cálculos científicos. Usamos num cuando queremos escribir una función que acepte tanto enteros como decimales sin importar el tipo exacto. Si eliges mal, podrías sufrir de pérdida de precisión (al usar double para dinero) o errores de ejecución (al intentar convertir un texto inválido a un número sin la precaución adecuada). Además, es crucial entender que, aunque en la VM nativa los int son enteros de 64 bits, si compilas para JavaScript, estos se representan como números de punto flotante, lo que limita la precisión de los enteros muy grandes.
void main() {
// --- Literales y formatos de escritura ---
int decimal = 42;
int hexadecimal = 0xFF; // 255
int binario = 0b1010; // 10
int conSeparador = 1_000_000; // Legibilidad para grandes cantidades
// --- Operaciones con int ---
int numeroBase = -15;
print('Valor absoluto: ${numeroBase.abs()}');
print('¿Es par?: ${numeroBase.isEven}');
print('¿Es impar?: ${numeroBase.isOdd}');
// gcd [disponible desde Dart 2.12] calcula el máximo común divisor
print('MCD de 48 y 18: ${48.gcd(18)}');
// --- Conversión segura de Strings ---
// tryParse es vital: si el string no es un número, devuelve null en lugar de lanzar error
int? n1 = int.tryParse('123');
int? n2 = int.tryParse('abc');
// --- Operaciones con double ---
double d = 3.14159;
print('Hacia abajo (floor): ${d.floor()}');
print('Hacia arriba (ceil): ${d.ceil()}');
print('Redondeo normal (round): ${d.round()}');
print('Dos decimales fijos: ${d.toStringAsFixed(2)}');
// --- Verificaciones especiales de double ---
double nanValue = double.nan;
double infValue = double.infinity;
print('¿Es NaN (Not a Number)?: ${nanValue.isNaN}');
print('¿Es infinito?: ${infValue.isInfinite}');
print('¿Es finito?: ${infValue.isFinite}');
// --- El tipo num y polimorfismo ---
// num puede almacenar tanto int como double
num mixto = 10;
mixto = 10.5;
// --- BigInt para precisión arbitraria ---
// Se usa cuando el número es demasiado grande para un int de 64 bits
BigInt gigante = BigInt.parse('999999999999999999999999999999');
print('Número astronómico: $gigante');
}
En el ejemplo anterior, vemos cómo la flexibilidad de num nos permite reasignar la variable mixto de un entero a un decimal sin problemas de tipos. Cuando trabajamos con la conversión de datos, la diferencia entre int.parse() e int.tryParse() es la diferencia entre un programa que se detiene bruscamente y uno que sabe manejar errores de forma elegante devolviendo null.
Para los cálculos con double, las funciones como floor() o ceil() son fundamentales para manipular el redondeo según la lógica de negocio. Por otro lado, si te encuentras trabajando con valores matemáticos extremadamente grandes, como en criptografía o cálculos astronómicos, BigInt es la única opción para evitar el desbordamiento de memoria, ya que gestiona la precisión de forma dinámica.
El tipo double sigue el estándar IEEE 754, lo que significa que es muy rápido para cálculos matemáticos, pero no es perfecto para representar ciertos decimales exactos.
El error frecuente
Un error clásico es intentar realizar comparaciones de igualdad directa con double cuando se realizan operaciones aritméticas previas. Debido a cómo la computadora maneja la precisión de punto flotante, esto suele fallar.
void main() {
double a = 0.1 + 0.2;
double b = 0.3;
// Esto será FALSE debido a la imprecisión de punto flotante
if (a == b) {
print('Son iguales');
} else {
print('No son iguales (error de precisión)');
}
}
Si necesitas comparar si dos números son “prácticamente iguales”, no uses ==. En su lugar, verifica que la diferencia entre ellos sea menor a un valor muy pequeño (llamado epsilon).
N° 12