2010-09-08 18 views
18

En JBox2d, existe el siguiente código para Vec2.equals():¿Por qué usar Float.floatToIntBits() en comparaciones de flotación de Java?

@Override 
public boolean equals(Object obj) { //automatically generated by Eclipse 
    if (this == obj) 
     return true; 
    if (obj == null) 
     return false; 
    if (getClass() != obj.getClass()) 
     return false; 
    Vec2 other = (Vec2) obj; 
    if (Float.floatToIntBits(x) != Float.floatToIntBits(other.x)) 
     return false; 
    if (Float.floatToIntBits(y) != Float.floatToIntBits(other.y)) 
     return false; 
    return true; 
} 

Me pregunto qué propósito el flotador < - funciones conversiones> int bits sirven, aquí. ¿Esto proporciona una forma de evitar el problema de inexactitud de la comparación de flotantes de Java (si es posible)? ¿O es algo completamente diferente? Me pregunto si es una alternativa al enfoque épsilon:

if (Math.abs(floatVal1 - floatVal2) < epsilon) 

PS. en aras de la exhaustividad y el interés, aquí está Vec2.hashCode():

@Override 
public int hashCode() { //automatically generated by Eclipse 
    final int prime = 31; 
    int result = 1; 
    result = prime * result + Float.floatToIntBits(x); 
    result = prime * result + Float.floatToIntBits(y); 
    return result; 
} 

FYI, puedo ver perfectamente por qué las funciones de conversión se utilizan en hashCode() - IDs de hash deben ser enteros.

Respuesta

21

La explicación puede encontrarse en Joshua Bloch's Effective Java: float y Float necesitan un tratamiento especial debido a la existencia de -0.0, NaN, infinito positivo e infinito negativo. Es por eso que la JVM de Sun Float.equals() se parece a esto (6u21):

public boolean equals(Object obj) 
{ 
    return (obj instanceof Float) 
      && (floatToIntBits(((Float)obj).value) == floatToIntBits(value)); 
} 

Así que no, Math.abs() con un épsilon no es una buena alternativa. Desde el Javadoc:

Si f1 y f2 ambos representan Float.NaN, entonces el método equals devuelve verdadero, a pesar de que Float.NaN == Float.NaN tiene el valor falso. Si f1 representa + 0.0f mientras que f2 representa -0.0f, o viceversa, la prueba igual tiene el valor falso, aunque 0.0f == - 0.0f tiene el valor verdadero.

Es por eso que el código autogenerado de Eclipse hace eso por usted.

+0

En otras palabras, ¿esto es completamente superior al enfoque épsilon? No puedo creer mi suerte, si es así. –

+0

Bueno, si puede garantizar que no obtendrá 'NaNs' o' -0.0' o infinitos, entonces el uso de 'Math.abs()

+1

Veo a partir de los comentarios a continuación que estaba confundiendo lo que hace. Resuelve problemas centrados alrededor de los valores float especiales; no se ocupa de la inexactitud del flotador, como usted indicó inicialmente en su respuesta. Entonces ignora mi última pregunta. –

10

Double.NaN (not-a-número) es un valor especial cuando se trata de la comparación:

System.out.println(Float.NaN == Float.NaN); 
System.out.println(Float.floatToIntBits(Float.NaN) == Float.floatToIntBits(Float.NaN)); 

Esta impresora:

false 
true 
2

No sé 100%, pero lo más probable es que estén tratando de evitar el problema NaN! = NaN. Si su flotador pasa a ser NaN, no se puede comparar con nada, ya que el resultado siempre es falso. La comparación de los intBits te dará NaN == NaN.

Cuestiones relacionadas