2010-09-30 19 views
16

Estoy usando un findbugs en un script ANT y no puedo encontrar la manera de corregir dos de mis errores. He leído la documentación, pero no entiendo. Aquí están mis errores y el código que los acompaña:Prueba de igualdad de coma flotante. (FE_FLOATING_POINT_EQUALITY)

Error 1: prueba de igualdad de coma flotante. (FE_FLOATING_POINT_EQUALITY)

private boolean equals(final Quantity other) { 
    return this.mAmount == convertedAmount(other); 
} 

error 2: EQ_COMPARETO_USE_OBJECT_EQUALS

public final int compareTo(final Object other) { 
    return this.description().compareTo(((Decision) other).description()); 
} 

he leído la documentación para la emisión ComparesTo que indica

Es muy recomendable, pero no es estrictamente necesario que (x.compareTo (y) == 0) == (x.equals (y)). En términos generales, cualquier clase que implemente la interfaz Comparable y viole esta condición debe indicar claramente este hecho. El lenguaje recomendado es "Nota: esta clase tiene un orden natural que es inconsistente con los iguales".

y también los documentos relativos a la igualdad de punto flotante

Esta operación compara dos valores de coma flotante por la igualdad. Debido a que los cálculos de coma flotante pueden implicar el redondeo, los valores flotantes y dobles calculados pueden no ser precisos. Para valores que deben ser precisos, como valores monetarios, considere usar un tipo de precisión fija como BigDecimal. Para valores que no necesitan ser precisos, considere comparar para igualdad dentro de algún rango, por ejemplo: if (Math.abs (x - y) < .0000001). Consulte la Especificación del lenguaje Java, sección 4.2.4.

No lo consigo. Alguien puede ayudarme porfavor?

Respuesta

15

Problema 1:

Para el tema FE_FLOATING_POINT_EQUALITY, que no debería ser la comparación de dos valores de coma flotante directamente con el operador ==, ya que debido a pequeños errores de redondeo, los valores podrían ser semánticamente "igual" para su aplicación incluso si la condición value1 == value2 no es verdadera.

Con el fin de solucionar este problema, modifique el código de la siguiente manera:

private boolean equals(final Quantity other) { 
    return (Math.abs(this.mAmount - convertedAmount(other)) < EPSILON); 
} 

Dónde EPSILON es una constante que se deben definir en su código, y representa las pequeñas diferencias que son aceptables para su aplicación, por ejemplo, .0000001.

Problema 2:

Para el tema EQ_COMPARETO_USE_OBJECT_EQUALS: Se recomienda encarecidamente que siempre que x.compareTo(y) devuelve cero, x.equals(y) debería ser true. En su código ha implementado compareTo, pero no ha anulado equals, por lo que está heredando la implementación de equals desde Object, y la condición anterior no se cumple.

Con el fin de solucionar este problema, anular equals (y tal vez hashCode) en su clase, de modo que cuando x.compareTo(y) devuelve 0, entonces x.equals(y) volverán true.

+3

Un método 'equals' debe ser transitiva (http://javarevisited.blogspot.fr/2011/02/ how-to-write-equals-method-in-java.html) y consistentes con el método 'hashCode'. Cuéntanos más acerca de tu implementación 'igual' como' (Math.abs (this.mAmount - convertedAmount (other))

+1

@PascalCuoq ¿ha resuelto esto? Una forma en que puedo pensar es convertir flotante a BigDecimal, redondear a la precisión que necesita y calcular el hash para eso. Pero habrá un impacto en el rendimiento. –

+1

@AlexanderMalakhov No soy la persona que hizo la pregunta. Solo hice un comentario acerca de la conveniencia de definir un método "igual" no transitivo. No hay problema para "resolver" aquí. Los valores de punto flotante se pueden aplicar a hash y se pueden comparar por igualdad con los operadores básicos que Java ya ofrece. Cualquiera que defina un método 'igual' no-transitivo se está creando un problema por sí mismo, y la forma más simple de resolver el problema es no crearlo en primer lugar. –

6

Para la advertencia de coma flotante, debe tener en cuenta que los flotadores son tipo inexacto. Una referencia estándar a menudo dada para esto (que vale la pena leer una vez) es:

What Every Computer Scientist Should Know About Floating-Point Arithmetic por David Goldberg.

Porque los flotantes no son valores exactos, incluso si miran lo mismo cuando se redondean a unos pocos decimales, pueden diferir muy poco y no coinciden.

El Comparable interface espera un cierto comportamiento de su implementador; la advertencia le dice que no se está adhiriendo a eso, y ofrece acciones sugeridas.

1

No estoy de acuerdo con las respuestas anteriores. Iguales y compare son el lugar equivocado para introducir épsilon en comparaciones de coma flotante.

Los valores de punto flotante se pueden comparar exactamente por iguales y compare, simplemente usando el operador "==".
Si su aplicación usa flotadores que son un resultado del cálculo, necesita comparar estos valores con el enfoque épsilon, debería hacerlo solo en ese lugar donde sea necesario. E.g en un método matemático de intersección de líneas.
Pero no en iguales y compare A.

Esta advertencia es muy engañosa. Significa comparar dos carrozas donde al principio uno es el resultado de un cálculo podría dar un resultado inesperado. Sin embargo, a menudo este tipo de flotadores, para comparar, no son el resultado de un cálculo, como

static final double INVALID_VALUE = -99.0; 
if (f == INVALID_VALUE) 

donde f es inicializado con INVALID_VALUE, será en Java siempre funcione a la perfección. Pero findbugs y sonarcube seguirán quejándose.

Entonces sólo tiene que añadir un filtro para ignorar findbugs, Asumiendo que tiene dos clases MyPoint2D y Myrectangle2D

<Match> 
     <OR> 
      <Class name="~.*\.MyPoint2D" /> 
      <Class name="~.*\.MyRectangle2D" /> 
     </OR> 
     <Bug code="FE" /> 
     <Justification author="My Name" /> 
     <Justification 
      text="Floating point equals works (here)." /> 
    </Match> 
+0

El uso de un "valor no válido" no es un enfoque limpio en primer lugar. Pero la optimización (a menudo hecha prematuramente) puede conducir a un hack e incluso podría ser la mejor solución al final. Desde el punto de vista del Código limpio, debería utilizar un campo separado que contenga la información de si el flotante es válido o no. Entonces no necesitarías pensar en revisar flotadores por igualdad. – Alfe

+0

Acepto, en muchas situaciones, es mejor tener un campo de juego aparte para mostrar la validez. En muchas otras situaciones no. (Código interno no público para ninguna otra clase) El tema principal aquí es que la comparación con las constantes de punto de floatin funciona – AlexWien

+0

La noción de que el código interno puede ser menos limpio es peligrosa. Además, el código interno puede necesitar mantenimiento por parte de un desarrollador sucesor que debe comprender el código. Pero aceptaré el argumento "altamente optimizado" en algunos casos. – Alfe

Cuestiones relacionadas