J'ai lu ce post zéro négatif et positif .
À ma compréhension, le code suivant devrait donner true
et true
en sortie.
Cependant, il donne false
et true
comme sortie.
Je compare un zéro négatif avec un zéro positif.
public class Test {
public static void main(String[] args) {
float f = 0;
float f2 = -f;
Float F = new Float(f);
Float F1 = new Float(f2);
System.out.println(F1.equals(F));
int i = 0;
int i2 = -i;
Integer I = new Integer(i);
Integer I1 = new Integer(i2);
System.out.println(I1.equals(I));
}
}
Pourquoi avons-nous un comportement différent pour les 0 pour Integer
et Float
?
i
eti2
sont exactement les mêmes. Ensuite, lorsque vous créez de nouveauxInteger
s, ils enveloppent tous les deux la même valeur exacte.I1.equals(I)
sera vrai.int i = Integer.MIN_VALUE, i2 = -i;
…new
les types d'encapsuleurs ici. Il suffit d'utiliser, par exempleInteger i = 0, i2 = -i; System.out.println(i.equals(i2)); Float f1 = 0f, f2 = -f1; System.out.println(f1.equals(f2));
Réponses:
Ints et flotteurs sont des bêtes assez différentes en Java. Les entiers sont codés comme un complément à deux , qui a une seule valeur 0. Les flotteurs utilisent IEEE 754 (la variante 32 bits pour les flottants et 64 bits pour les doubles). IEEE 754 est quelque peu complexe, mais pour les besoins de cette réponse, il vous suffit de savoir qu'il comporte trois sections, dont la première est un bit de signe. Cela signifie que pour tout flotteur, il existe une variante positive et négative¹. Cela inclut 0, donc les flottants ont en fait deux valeurs "zéro", +0 et -0.
Soit dit en passant, le complément à deux que les ints utilisent n'est pas le seul moyen de coder des entiers en informatique. Il existe d'autres méthodes, comme celles de complément , mais elles ont des bizarreries - comme avoir à la fois un +0 et -0 comme valeurs distinctes. ;-)
Lorsque vous comparez des primitives flottantes (et doubles), Java traite +0 et -0 comme égaux. Mais lorsque vous les encadrez, Java les traite séparément, comme décrit dans
Float#equals
. Cela permet à la méthode equals d'être cohérente avec leurhashCode
implémentation (ainsi quecompareTo
), qui utilise simplement les bits du float (y compris cette valeur signée) et les pousse tels quels dans un int.Ils auraient pu choisir une autre option pour equals / hashCode / compareTo, mais ils ne l'ont pas fait. Je ne sais pas quelles étaient les considérations de conception. Mais à au moins un égard,
Float#equals
allait toujours diverger de la primitive flottante==
: dans les primitivesNaN != NaN
, mais pour tous les objets, celao.equals(o)
doit aussi être vrai . Cela signifie que si vous l'aviezFloat f = Float.NaN
, alorsf.equals(f)
même sif.floatValue() != f.floatValue()
.¹ Les valeurs NaN (pas un nombre) ont un bit de signe, mais il n'a pas d'autre signification que pour la commande, et Java l'ignore (même pour la commande).
la source
Ceci est l'un des Float est égal à l'exception
Le pourquoi est également décrit:
-0 et 0 seront représentés différemment en utilisant le bit 31 de Float:
Ce n'est pas le cas
Integer
la source
Pour les entiers, il n'y a pas de distinction entre -0 et 0 pour les entiers car il utilise la représentation du compliment Twos . Donc, votre exemple entier
i
eti1
sont exactement les mêmes.Pour les flottants, il y a une représentation -0, et sa valeur est équivalente à 0, mais la représentation binaire est différente. Par conséquent, le nouveau flotteur (0f) et le nouveau flotteur (-0f) auraient des représentations différentes.
Vous pouvez voir la différence dans les représentations de bits.
Et si vous laissez le
f
pour déclarer le,-0f
il sera traité comme un entier et vous ne verrez aucune différence dans la sortie.la source
0.0f == -0.0f
. Donc, le comportement différent n'est que dansjava.lang.Float
.float
, qui est conforme à IEEE754 à cet égard etjava.lang.Float
, qui ne le fait pas. La différence dans la représentation des bits ne suffit donc pas à expliquer cela.