Comparando valores dobles en C#
Tengo una double
variable llamada x
. En el código, x
se le asigna un valor de 0.1
y lo verifico en una declaración 'si' comparando x
y0.1
if (x==0.1)
{
----
}
Lamentablemente no entra en el if
estado de cuenta.
¿Debo usar
Double
odouble
?¿Cuál es la razón detrás de esto? ¿Puedes sugerir una solución para esto?
Es un problema estándar debido a cómo la computadora almacena valores de punto flotante. Busque aquí "problema de punto flotante" y encontrará toneladas de información.
En resumen, un flotador/doble no puede almacenar 0.1
con precisión. Siempre estará un poco apagado.
Puedes intentar usar el decimal
tipo que almacena números en notación decimal. Así 0.1
será representable con precisión.
Querías saber el motivo:
Float/double se almacenan como fracciones binarias, no fracciones decimales. Para ilustrar:
12.34
en notación decimal (lo que usamos) significa
1 * 10 1 + 2 * 10 0 + 3 * 10 -1 + 4 * 10 -2
La computadora almacena números de coma flotante de la misma manera, excepto que usa base 2
: 10.01
significa
1 * 2 1 + 0 * 2 0 + 0 * 2 -1 + 1 * 2 -2
Ahora bien, probablemente sepas que hay algunos números que no se pueden representar completamente con nuestra notación decimal. Por ejemplo, 1/3
en notación decimal es 0.3333333…
. Lo mismo ocurre en notación binaria, excepto que los números que no se pueden representar con precisión son diferentes. Entre ellos está el número 1/10
. En notación binaria, eso es 0.000110011001100…
.
Dado que la notación binaria no puede almacenarlo con precisión, se almacena de forma redondeada. De ahí tu problema.
double
y Double
son iguales ( double
es un alias de Double
) y se pueden usar indistintamente.
El problema al comparar un valor doble con otro valor es que los dobles son valores aproximados, no valores exactos. Entonces, cuando lo configura, x
en 0.1
realidad puede almacenarse como 0.100000001
algo así.
En lugar de verificar la igualdad, debe verificar que la diferencia sea menor que una diferencia mínima definida (tolerancia). Algo como:
if (Math.Abs(x - 0.1) < 0.0000001)
{
...
}
Necesitas una combinación de Math.Abs
on X-Y
y a value
para comparar.
Puede utilizar el siguiente método de extensión
public static class DoubleExtensions
{
const double _3 = 0.001;
const double _4 = 0.0001;
const double _5 = 0.00001;
const double _6 = 0.000001;
const double _7 = 0.0000001;
public static bool Equals3DigitPrecision(this double left, double right)
{
return Math.Abs(left - right) < _3;
}
public static bool Equals4DigitPrecision(this double left, double right)
{
return Math.Abs(left - right) < _4;
}
...
Dado que rara vez se llaman métodos en doble, excepto que ToString
creo que es una extensión bastante segura.
Entonces puedes comparar x
y y
darle me gusta.
if(x.Equals4DigitPrecision(y))