web-dev-qa-db-fra.com

Pourquoi Double.compare de Java (double, double) est-il implémenté tel quel?

Je regardais l'implémentation de compare (double, double) dans la bibliothèque Java standard (6). Elle se lit comme suit:

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)
}

Quels sont les mérites de cette mise en œuvre?


edit: "Merits" était un (très) mauvais choix de mots. Je voulais savoir comment cela fonctionne.

35
DavidS

@ La réponse de Shoover est correcte (lisez-la!), Mais il y a un peu plus que cela.

Comme l'indique javadoc pour Double::equals:

"Cette définition permet aux tables de hachage de fonctionner correctement."

Supposons que les concepteurs Java Java ont décidé d'implémenter equals(...) et compare(...) avec la même sémantique que == Sur le double instances. Cela signifierait que equals() renverrait toujours false pour un NaN encapsulé. Réfléchissez maintenant à ce qui se passerait si vous tentiez d'utiliser un NaN encapsulé dans une carte ou une collection.

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.
}

Cela n'a pas beaucoup de sens, n'est-ce pas?

D'autres anomalies existeraient car -0.0 Et +0.0 Ont des modèles de bits différents mais sont égaux selon ==.

Ainsi, les concepteurs Java Java ont décidé (à juste titre IMO) de la définition plus compliquée (mais plus intuitive) de ces méthodes doubles que nous avons aujourd'hui.

41
Stephen C

L'explication se trouve dans les commentaires du code. Java a des valeurs doubles pour 0.0 Et -0.0, Ainsi que "pas un nombre" (NaN). Vous ne pouvez pas utilisez l'opérateur simple == pour ces valeurs. Jetez un œil à la source doubleToLongBits() et à Javadoc pour la méthode Double.equals() :

Notez que dans la plupart des cas, pour deux instances de la classe Double, d1 Et d2, La valeur de d1.equals(d2) est true si et seulement si

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

a également la valeur true. Cependant, il existe deux exceptions:

  • Si d1 Et d2 Représentent tous les deux Double.NaN, La méthode equals renvoie true, même si Double.NaN == Double.NaN A la valeur false.
  • Si d1 Représente +0.0 Tandis que d2 Représente -0.0, Ou vice versa, le test égal a la valeur false, même si +0.0 == -0.0 A la valeur true.

Cette définition permet aux tables de hachage de fonctionner correctement.

43
shoover

Le mérite est que c'est le code le plus simple qui remplit la spécification.

Une caractéristique commune des programmeurs débutants est de surévaluer la lecture du code source et de sous-évaluer la lecture des spécifications . Dans ce cas, la spécification:

http://Java.Sun.com/javase/6/docs/api/Java/lang/Double.html#compareTo%28Java.lang.Double%29

... rend le comportement et la raison du comportement (cohérence avec equals ()) parfaitement clairs.

2
Kevin Bourrillion

Cette implémentation permet de définir un nombre réel comme <NaN et -0,0 comme <0,0.

0
phoebus