He leído este post negativo y cero positivo .
A mi entender, el siguiente código debería dar true
y true
como salida.
Sin embargo, está dando false
y true
como salida.
Estoy comparando el cero negativo con un cero positivo.
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));
}
}
¿Por qué tenemos un comportamiento diferente para 0's para Integer
y Float
?
i
yi2
son exactamente lo mismo Luego, cuando crea nuevosInteger
correos electrónicos, ambos envuelven exactamente el mismo valor.I1.equals(I)
será verdadint i = Integer.MIN_VALUE, i2 = -i;
...new
para los tipos de envoltura aquí. Solo use, por ejemploInteger i = 0, i2 = -i; System.out.println(i.equals(i2)); Float f1 = 0f, f2 = -f1; System.out.println(f1.equals(f2));
Respuestas:
Ints y flotantes son bestias bastante diferentes en Java. Los Ints se codifican como complemento de dos , que tiene un solo valor 0. Los flotantes usan IEEE 754 (la variante de 32 bits para flotantes y 64 bits para dobles). IEEE 754 es algo complejo, pero para el propósito de esta respuesta, solo necesita saber que tiene tres secciones, la primera de las cuales es un bit de signo. Eso significa que para cualquier flotador, hay una variante positiva y negativa¹. Eso incluye 0, por lo que los flotadores en realidad tienen dos valores "cero", +0 y -0.
Por otro lado, el complemento de dos que usa ints no es la única forma de codificar enteros en informática. Existen otros métodos, como el complemento de uno , pero tienen peculiaridades, como tener un +0 y -0 como valores distintos. ;-)
Cuando compara primitivas flotantes (y dobles), Java trata a +0 y -0 como iguales. Pero cuando los encajona, Java los trata por separado, como se describe en
Float#equals
. Esto permite que el método equals sea coherente con suhashCode
implementación (así como tambiéncompareTo
), que solo usa los bits del flotante (incluido ese valor con signo) y los inserta tal cual en un int.Podrían haber elegido alguna otra opción para equals / hashCode / compareTo, pero no lo hicieron. No estoy seguro de cuáles fueron las consideraciones de diseño. Pero al menos en un aspecto,
Float#equals
siempre iba a divergir de los primitivos flotantes==
: en primitivosNaN != NaN
, pero para todos los objetos,o.equals(o)
también debe ser cierto . Eso significa que si tuvierasFloat f = Float.NaN
,f.equals(f)
aunquef.floatValue() != f.floatValue()
.Values Los valores NaN (no un número) tienen un bit de signo, pero no tiene otro significado que no sea para ordenar, y Java lo ignora (incluso para ordenar).
fuente
Esta es una de flotación igual a excepción
El por qué se describe también:
-0 y 0 se representarán de manera diferente usando el bit 31 de Float:
Este no es el caso en
Integer
fuente
Para los enteros, no hay distinción entre -0 y 0 para los enteros porque utiliza la representación de complemento de Twos . Entonces su ejemplo entero
i
yi1
son exactamente iguales.Para los flotantes, hay una representación -0, y su valor es equivalente a 0, pero la representación de bits es diferente. Por lo tanto, el nuevo Float (0f) y el nuevo Float (-0f) tendrían diferentes representaciones.
Puede ver la diferencia en las representaciones de bits.
Y si deja de
f
declarar-0f
, se tratará como un entero y no verá ninguna diferencia en la salida.fuente
0.0f == -0.0f
. Entonces, el comportamiento diferente solo está enjava.lang.Float
.float
, que se ajusta a IEEE754 a este respecto yjava.lang.Float
que no. Entonces, la diferencia en la representación de bits no es suficiente para explicar esto.