float - double compare java
¿Por qué se implementa Double.compare(doble, doble) de Java tal como es? (4)
El mérito es que es el código más simple que cumple con la especificación.
Una característica común de los programadores novatos es sobrevalorar el código fuente de lectura y subestimar las especificaciones de lectura. En este caso, la especificación:
http://java.sun.com/javase/6/docs/api/java/lang/Double.html#compareTo%28java.lang.Double%29
... hace que el comportamiento y la razón del comportamiento (coherencia con igual ()) sean perfectamente claros.
Estaba mirando la implementación de comparar (doble, doble) en la biblioteca estándar de Java (6). Se lee:
public static int compare(double d1, double d2) {
if (d1 < d2)
return -1; // Neither val is NaN, thisVal is smaller
if (d1 > d2)
return 1; // Neither val is NaN, thisVal is larger
long thisBits = Double.doubleToLongBits(d1);
long anotherBits = Double.doubleToLongBits(d2);
return (thisBits == anotherBits ? 0 : // Values are equal
(thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
1)); // (0.0, -0.0) or (NaN, !NaN)
}
¿Cuáles son los méritos de esta implementación?
editar: "Méritos" fue una (muy) mala elección de palabras. Quería saber cómo funciona esto.
Esa implementación permite que un número real se defina como <NaN y -0.0 como <0.0.
La explicación está en los comentarios en el código. Java tiene valores dobles para 0.0
y -0.0
, así como "no un número" ( NaN
). No puede usar el operador simple ==
para estos valores. Eche un vistazo a la fuente doubleToLongBits()
y al Javadoc para el método Double.equals()
:
Tenga en cuenta que en la mayoría de los casos, para dos instancias de la clase
Double
,d1
yd2
, el valor ded1.equals(d2)
estrue
si y solo si
d1.doubleValue() == d2.doubleValue()
también tiene el valor
true
. Sin embargo, hay dos excepciones:
- Si
d1
yd2
representan ambosDouble.NaN
, el método equals devuelvetrue
, aunqueDouble.NaN == Double.NaN
tiene el valorfalse
.- Si
d1
representa+0.0
mientrasd2
representa-0.0
, o viceversa, la prueba igual tiene el valorfalse
, aunque+0.0 == -0.0
tiene el valortrue
.Esta definición permite que las tablas hash funcionen correctamente.
La respuesta de @ Shoover es correcta, pero hay algo más que esto.
Como el javadoc para Double::equals
estados:
"Esta definición permite que las tablas hash funcionen correctamente".
Supongamos que los diseñadores de Java decidieron implementar equals(...)
y compare(...)
con la misma semántica que ==
en las instancias double
envueltas. Esto significa que equals()
siempre devolvería false
para un NaN envuelto. Ahora considere lo que sucedería si tratara de usar un NaN envuelto en un Mapa o Colección.
List<Double> l = new ArrayList<Double>();
l.add(Double.NaN);
if (l.contains(Double.NaN)) {
// this wont be executed.
}
Map<Object,String> m = new HashMap<Object,String>();
m.put(Double.NaN, "Hi mum");
if (m.get(Double.NaN) != null) {
// this wont be executed.
}
No tiene mucho sentido, ¿verdad?
Otras anomalías existirían porque -0.0
y +0.0
tienen patrones de bits diferentes, pero son iguales según ==
.
Entonces, los diseñadores de Java decidieron (con razón IMO) en la definición más complicada (pero más intuitiva) para estos métodos Double que tenemos hoy.