1. Introducción
Parece que si el ordenador es "listo", entonces 0.1 + 0.2 debería ser simplemente 0.3. Pero no es exactamente así. Vamos a verlo con un ejemplo sencillo.
double x = 0.1;
double y = 0.2;
double sum = x + y;
Console.WriteLine(sum); // ¿Qué va a mostrar el programa?
Ahora intenta comparar con 0.3:
Console.WriteLine(sum == 0.3); // ¿Aquí será true o false?
Si ves False, ¡no te sorprendas!
La razón está en cómo se representan los números en la memoria
Los ordenadores trabajan con números en sistema binario. Pero no todas las fracciones decimales se pueden representar como fracciones binarias finitas, igual que 1/3 no se puede escribir exactamente en decimal (0.333...). Por ejemplo, 0.1 en binario es una fracción infinita, y hay que "redondearla" para guardarla.
Dicho en palabras simples, double a veces "finge" que guarda tu número exactamente, pero en realidad solo almacena un valor muy aproximado.
2. ¿Qué "fallos" pueden pasar con la aritmética de double?
Vamos a ver ejemplos prácticos.
Ejemplo 1. La clásica "magia" de 0.1 + 0.2
double a = 0.1;
double b = 0.2;
double sum = a + b;
Console.WriteLine(sum); // 0.30000000000000004
Console.WriteLine(sum == 0.3); // False
El ordenador no mostró 0.3, sino 0.30000000000000004. La diferencia es pequeña, pero si trabajas, por ejemplo, con finanzas — ya es crítico.
Ejemplo 2. Suma iterativa
double result = 0;
for (int i = 0; i < 10; i++)
{
result += 0.1;
}
Console.WriteLine(result); // 0.9999999999999999
Querías 1.0 — salió un poco menos. Otra vez, la razón es el redondeo dentro de double.
Por qué esto importa en problemas reales
Muchos piensan: "¿Qué más da, es un error pequeño, no pasa nada!" Vamos a ver un ejemplo del mundo de los pagos.
Supón que tu banco online suma 100 transacciones de 0.1 euros cada una. Si tu programa "pierde" una cienmilésima de euro en cada iteración, a escala de banco ya "pierdes" dinero real. Y ahí enseguida viene el contable y te pregunta: "¿Dónde está nuestro dinero?!"
3. Cómo comparar correctamente números reales
Como double muchas veces no puede guardar exactamente el valor que esperas, la comparación directa con == puede fallar. En vez de eso, se suele comparar el valor absoluto de la diferencia con un número muy pequeño (epsilon).
Ejemplo de comparación con tolerancia
double a = 0.1 + 0.2;
double b = 0.3;
double epsilon = 0.000001;
if (Math.Abs(a - b) < epsilon)
{
Console.WriteLine("¡Casi igual!"); // Así es más seguro comparar
}
Aquí decimos: "Si la diferencia entre los números es menor que una millonésima, consideramos que son iguales".
4. Valores especiales de double: Infinity, NaN, -Infinity
El tipo double no solo guarda números, sino también valores especiales. Aparecen en situaciones que un matemático le prohibiría a cualquier estudiante.
Infinito (Infinity)
¿Qué pasa si divides 1 entre 0?
double result = 1.0 / 0.0;
Console.WriteLine(result); // Infinity
En C# (y en muchos lenguajes) dividir por 0 para double no lanza excepción. En vez de eso, el resultado es el valor especial "infinito positivo".
Menos infinito (-Infinity)
Si divides un número negativo por 0, obtienes infinito negativo:
double result = -1.0 / 0.0;
Console.WriteLine(result); // -Infinity
"No es un número" (NaN — Not a Number)
Si haces algo muy raro, como intentar calcular la raíz de un número negativo:
double result = Math.Sqrt(-1);
Console.WriteLine(result); // NaN
O el resultado de dividir 0.0 / 0.0:
double result = 0.0 / 0.0;
Console.WriteLine(result); // NaN
NaN — es "todo lo que no sería un número en la vida real".
Comprobando valores especiales
En C# hay funciones para comprobar valores especiales:
Console.WriteLine(double.IsInfinity(result)); // true si es infinito
Console.WriteLine(double.IsNaN(result)); // true si es NaN
Tabla: Cómo reacciona double a operaciones raras
| Operación | Resultado | Qué guarda double |
|---|---|---|
|
Infinity | +∞ |
|
-Infinity | -∞ |
|
NaN | No es un número |
|
NaN | No es un número |
GO TO FULL VERSION