Comparando números en Java

En Java, todos los tipos numéricos se extienden desde java.lang.Number. ¿Sería una buena idea tener un método como el siguiente?

public boolean areEqual(Number first, Number second) { if (first != null && second != null) { return first.equals(second); } } 

Me preocupan los casos en que un doble 2.00000 no es igual a un int 2. ¿Los maneja el igual incorporado? Si no, ¿hay alguna forma de escribir una función simple de comparación de números en java? (bibliotecas externas como Apache commons están bien)

Un Double NUNCA es equals a un Integer . Además, un double no es lo mismo que un Double .

Java tiene tipos primitivos y tipos de referencia. Los verdaderos tipos numéricos en Java no se extienden desde Number , porque son primitivos.

Es posible que desee considerar un sistema en el que no esté mezclando tipos, ya que generalmente causará muchos problemas con las conversiones implícitas / explícitas que pueden perder información, etc.

Preguntas relacionadas

En int vs Integer :

  • ¿Cuál es la diferencia entre un int y un entero en Java / C #?
  • ¿Está Java completamente orientado a objetos?

En la comparación de Number :

  • ¿Por qué java.lang.Number no implementa Comparable ?
  • Comparando los valores de dos números generics

Ver también

  • Guía de lenguaje Java / Autoboxing
  • JLS 4.2 4.2 Tipos y valores primitivos

    Los tipos numéricos son los tipos integrales y los tipos de coma flotante. Los tipos integrales son byte , short , int , y long y char . Los tipos de punto float son float y double .


En el cómputo de tipo mixto

La computación de tipo mixto es el tema de al menos 4 rompecabezas en Java Puzzlers .

Aquí hay varios extractos:

en general, es mejor evitar los cálculos de tipo mixto porque son intrínsecamente […] confusos […] En ninguna parte es esto más aparente que en las expresiones condicionales. Las comparaciones de tipo mixto siempre son confusas porque el sistema se ve obligado a promover un operando para que coincida con el tipo del otro. La conversión es invisible y es posible que no arroje los resultados que espera

Prescripción : evite cálculos que mezclen tipos integrales y de coma flotante. Prefiere la aritmética integral al punto flotante.

Sé que es un tema antiguo, pero … Para comparar dos números en Java, puede usar el método compareTo de BigDecimal. BigDecimal puede contener desde corto hasta doble o BigInteger, por lo que es la clase perfecta para esto.

Entonces puedes intentar escribir algo como esto:

 public int compareTo(Number n1, Number n2) { // ignoring null handling BigDecimal b1 = new BigDecimal(n1.doubleValue()); BigDecimal b2 = new BigDecimal(n2.doubleValue()); return b1.compareTo(b2); } 

Este seguramente no es el mejor enfoque con respecto al rendimiento. Las siguientes pruebas funcionaron hasta ahora, al menos con JDK7:

 assertTrue(compareTo(new Integer(1), new Integer(2)) == -1); assertTrue(compareTo(new Integer(1), new Double(2.0)) == -1); assertTrue(compareTo(new Integer(1), new Double(Double.MAX_VALUE)) == -1); assertTrue(compareTo(new Integer(1), new Double(Double.MIN_VALUE)) == 1); assertTrue(compareTo(new Integer(1), new Double(1.000001)) == -1); assertTrue(compareTo(new Integer(1), new Double(1.000)) == 0); assertTrue(compareTo(new Integer(1), new Double(0.25*4)) == 0); assertTrue(compareTo(new Integer(1), new AtomicLong(1)) == 0); 

El método específico que sugiera fallará, porque está usando equals() heredado de Object . Es decir, comprobaría si los objetos Number eran los mismos, no si sus valores eran los mismos.

Si eso fuera solo un ejemplo ilustrativo, actualizaré mi respuesta.

La respuesta de Polygene en realidad cubre bastante bien el terreno al que me dirigía. También puede interesarle esta pregunta: ¿Por qué java.lang.Number no implementa Comparable? .

Si desea saber si las referencias a los objetos son las mismas, entonces los métodos existentes se ajustan a la factura. Un Double representa 2.0 y un Integer representa 2 son definitivamente objetos diferentes, y ciertamente no intercambiables en un sentido general.

Si solo desea saber si los valores numéricos son los mismos, puede usar el método Number.doubleValue () para convertir ambos números a dobles, luego compare esos números (probablemente permitiendo una tolerancia pequeña, ya que la mayoría de los números están representados inexactamente , como 1.99999999996583 para lo que debería ser 2, según los pasos de cálculo intermedios). Algo como lo siguiente:

 private static final double EPSILON = 0.000000000000001d; public static boolean areEquivalentNumbers(Number a, Number b) { if (a == null) { return b == null; } else if (b == null) { return false; } else { return Math.abs(a.doubleValue() - b.doubleValue()) < EPSILON; } } 

Comparar números entre enteros y puntos flotantes casi nunca va a dar lo que busca. Sin embargo, si se trata de un ejercicio simple, puede implementar la comparación comparando las representaciones de cadena de los valores, como en:

 public boolean areEqual(Number first, Number second) { if (first == null) { return second == null; } if (second == null) { return false; } return first.toString().equals(second.toString()); } 

En una tangente a un par de respuestas, sugiero que en lugar de escribir algo como:

 boolean compare(Object o1, Object o2) { if (o1==null) return o2==null; if (o2==null) return false; return o1.equals(o2); } 

Es mucho más conciso, y creo un poco más eficiente, escribir:

 boolean compare(Object o1, Object o2) { return o1==o2 || o1!=null && o2!=null && o1.equals(o2); } 

Si ambos son nulos, o1 == o2 devolverá verdadero. Si no lo son pero son el mismo objeto, está bien también.

Técnicamente, el o2! = Null no es necesario para la mayoría de las implementaciones de iguales, pero si realmente estuvieras siendo tan genérico como para hacer esto en Objetos como en el ejemplo anterior, por supuesto no sabrías cómo se escribieron todas las anulaciones.

no puedes llamar

 number.equals(number2); 

porque, si number es un Double y number2 es un Entero, no serán de la misma clase y obtendrás una excepción indicándote ese hecho.

Podría escribir usted mismo una clase de comparación que acepte objetos numéricos, pero deberá tener en cuenta las diferentes subclases de Número