BigDecimal es igual a () versus compareTo ()

157

Considere la clase de prueba simple:

import java.math.BigDecimal;

/**
 * @author The Elite Gentleman
 *
 */
public class Main {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        BigDecimal x = new BigDecimal("1");
        BigDecimal y = new BigDecimal("1.00");
        System.out.println(x.equals(y));
        System.out.println(x.compareTo(y) == 0 ? "true": "false");
    }

}

Puede (conscientemente) decir que xes igual a y(no referencia de objeto), pero cuando ejecuta el programa, el siguiente resultado muestra:

false
true

Pregunta: ¿Cuál es la diferencia entre compareTo()y equals()en BigDecimalque compareTopuede determinar que xes igual a y?

PD: Veo que BigDecimal tiene un inflate()método en equals()método. ¿Qué hace en inflate()realidad?

Buhake Sindi
fuente
1
Anuncio inflate(): no es parte de la API pública porque solo manipula la representación interna y no tiene ningún efecto visible en el "exterior". Entonces, a menos que realmente desee estudiar la implementación BigDecimalen profundidad, le sugiero que ignore este método.
Joachim Sauer
Una breve explicación y fragmentos de código fuente se pueden encontrar aquí
xenteros

Respuestas:

224

La respuesta está en el JavaDoc del equals()método :

A diferencia compareTo, este método considera dos BigDecimalobjetos iguales solo si son iguales en valor y escala (por lo tanto, 2.0 no es igual a 2.00 en comparación con este método).

En otras palabras: equals()comprueba si los BigDecimalobjetos son exactamente iguales en todos los aspectos. compareTo()"solo" compara su valor numérico.

En cuanto a por qué se equals() comporta de esta manera, esto se ha respondido en esta pregunta SO .

Joachim Sauer
fuente
24
Esa es una parte muy complicada de BigDecimalsi no lee el JavaDoc con cuidado. :) - Obtuvimos algunos errores extraños de esto hasta que nos dimos cuenta de la diferencia.
Thomas
3
Muchas partes de la API estándar actúan "sin intuición", cuando lo intuitivo no sería correcto. BigDecimalEs una de esas cosas. Por lo tanto, siempre se debe verificar el JavaDoc. Al menos una vez que descubres que algo extraño está sucediendo.
Joachim Sauer
77
Gracioso. Después de leer su respuesta, acabo de marcar Comparable y dice que la consistencia con iguales "es muy recomendable (pero no obligatorio)"
SJuan76
44
He preguntado por qué: stackoverflow.com/questions/14102083/…
bacar
8
@StephenC Creo que es incorrecto que exista esta inconsistencia.
Matt R
1

Veo que BigDecimal tiene un método inflate () en el método equals (). ¿Qué hace realmente inflar ()?

Básicamente, inflate()llama BigInteger.valueOf(intCompact)si es necesario, es decir, crea el valor sin escala que se almacena como BigIntegerdesde long intCompact. Si no lo necesita BigIntegery el valor sin escala se ajusta a un, long BigDecimalparece que intenta ahorrar espacio el mayor tiempo posible.

Thomas
fuente
No tengo idea de lo que escribiste (especialmente con la última oración).
Buhake Sindi
@The Elite Gentlement La última oración solo debería decir que internamente BigDecimalmantiene su valor sin escala tanto en un longcomo en un BigInteger. Si BigIntegerno se necesita internamente, no se crea, pero si es necesario (por ejemplo, cuando se equalsencuentra un inflado inflado y no inflado BigDecimal) () se usa para crearlo. - Para resumir: inflate()maneja las conversiones internas si es necesario y ya es privado, no debería importar a los usuarios de la clase.
Thomas
1

Creo que la respuesta correcta sería hacer que los dos números (BigDecimals) tengan la misma escala y luego podamos decidir sobre su igualdad. Por ejemplo, ¿son iguales estos dos números?

1.00001 and 1.00002

Bueno, depende de la escala. En la escala 5 (5 puntos decimales), no, no son lo mismo. pero en precisiones decimales más pequeñas (escala 4 e inferior) se consideran iguales. Así que sugiero que la escala de los dos números sea igual y luego compararlos.

Mr.Q
fuente
-10

También puedes comparar con doble valor

BigDecimal a= new BigDecimal("1.1"); BigDecimal b =new BigDecimal("1.1");
System.out.println(a.doubleValue()==b.doubleValue());
Rashmi singh
fuente
55
Evite esta solución tanto como sea posible. Incluso los dobles deben compararse con "epsilon". No tiene sentido tener BigDecimal y compararlo como dobles ... hay una probabilidad muy alta de que le dispares a tu propia pierna.
Vadim Kirilchuk
Los valores de los dobles se deben comparar usando epsillons
Bishwajit Purkaystha