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.
@ 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.
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
Etd2
, La valeur ded1.equals(d2)
esttrue
si et seulement sid1.doubleValue() == d2.doubleValue()
a également la valeur
true
. Cependant, il existe deux exceptions:
- Si
d1
Etd2
Représentent tous les deuxDouble.NaN
, La méthode equals renvoietrue
, même siDouble.NaN == Double.NaN
A la valeurfalse
.- Si
d1
Représente+0.0
Tandis qued2
Représente-0.0
, Ou vice versa, le test égal a la valeurfalse
, même si+0.0 == -0.0
A la valeurtrue
.Cette définition permet aux tables de hachage de fonctionner correctement.
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.
Cette implémentation permet de définir un nombre réel comme <NaN et -0,0 comme <0,0.