float java comparison floating-point

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 y d2 , el valor de d1.equals(d2) es true si y solo si

d1.doubleValue() == d2.doubleValue()

también tiene el valor true . Sin embargo, hay dos excepciones:

  • Si d1 y d2 representan ambos Double.NaN , el método equals devuelve true , aunque Double.NaN == Double.NaN tiene el valor false .
  • Si d1 representa +0.0 mientras d2 representa -0.0 , o viceversa, la prueba igual tiene el valor false , aunque +0.0 == -0.0 tiene el valor true .

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.