BigDecimal równa się () a porównajTo ()

157

Rozważmy prostą klasę testową:

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");
    }

}

Możesz (świadomie) powiedzieć, że xto jest równe y(nie odwołanie do obiektu), ale po uruchomieniu programu zobaczysz następujący wynik:

false
true

Pytanie: Jaka jest różnica między compareTo()i equals()w BigDecimaltym, że compareTomożna określić, że xjest równa y?

PS: Widzę, że BigDecimal ma inflate()metodę na equals()metodę. Co inflate()właściwie robi?

Buhake Sindi
źródło
1
Reklama inflate(): nie jest częścią publicznego API, ponieważ manipuluje tylko wewnętrzną reprezentacją i nie ma widocznego wpływu na „zewnątrz”. Więc jeśli naprawdę nie chcesz BigDecimaldogłębnie przestudiować implementacji , proponuję zignorować tę metodę.
Joachim Sauer
Krótkie wyjaśnienie i fragmenty kodu źródłowego można znaleźć tutaj
xenteros

Odpowiedzi:

224

Odpowiedź znajduje się w JavaDoc equals()metody :

W przeciwieństwie do compareTotej metody uważa się, że dwa BigDecimalobiekty są równe tylko wtedy, gdy mają taką samą wartość i skalę (w związku z tym 2,0 nie jest równe 2,00 w porównaniu z tą metodą).

Innymi słowy: equals()sprawdza, czy BigDecimalobiekty są dokładnie takie same pod każdym względem. compareTo()„tylko” porównuje ich wartość liczbową.

Co do tego, dlaczego equals() zachowuje się w ten sposób, odpowiedź na to pytanie prejudycjalne została udzielona .

Joachim Sauer
źródło
24
To bardzo trudna część, BigDecimaljeśli nie przeczytasz uważnie JavaDoc. :) - Mamy z tego jakieś dziwne błędy, dopóki nie zauważyliśmy różnicy.
Thomas
3
Wiele części standardowego API działa „nieintuicyjnie”, gdy intuicyjna rzecz nie byłaby poprawna. BigDecimalto jedna taka rzecz. Dlatego zawsze należy sprawdzić JavaDoc. Przynajmniej kiedy się dowiesz, że dzieje się coś dziwnego.
Joachim Sauer
7
Zabawny. Po przeczytaniu twojej odpowiedzi właśnie zaznaczyłem Porównywalne i stwierdzono, że spójność z równymi sobie „jest zdecydowanie zalecana (ale nie wymagana)”
SJuan76
4
Zapytałem dlaczego: stackoverflow.com/questions/14102083/ ...
bacar
8
@StephenC Myślę, że to niepoprawne, że istnieje ta niespójność.
Matt R,
1

Widzę, że BigDecimal ma metodę inflate () w metodzie equals (). Co właściwie robi inflate ()?

Zasadniczo inflate()wywołuje w BigInteger.valueOf(intCompact)razie potrzeby, tj. Tworzy nieskalowaną wartość, która jest przechowywana jako BigIntegerfrom long intCompact. Jeśli tego nie potrzebujesz, BigIntegera nieskalowana wartość pasuje do a, long BigDecimalwydaje się, że staraj się oszczędzać miejsce tak długo, jak to możliwe.

Tomasz
źródło
Nie mam pojęcia, co napisałeś (zwłaszcza z ostatnim zdaniem).
Buhake Sindi
@ Elitarna delikatność Ostatnie zdanie powinno po prostu powiedzieć, że wewnętrznie BigDecimalzachowuje swoją nieskalowaną wartość longzarówno w a BigInteger. Jeśli BigIntegernie jest potrzebne wewnętrznie, nie jest tworzone, ale jeśli jest potrzebne (np. Gdy equalsnapotyka napompowane i nienadmuchane BigDecimal) inflate () `jest używane do jego utworzenia. - Podsumowując: inflate()obsługuje konwersje wewnętrzne w razie potrzeby i ponieważ jest prywatne, nie powinno mieć znaczenia dla użytkowników tej klasy
Thomas
1

Uważam, że poprawną odpowiedzią byłoby uczynienie tych dwóch liczb (BigDecimals) tą samą skalą, a następnie możemy zdecydować o ich równości. Na przykład, czy te dwie liczby są równe?

1.00001 and 1.00002

To zależy od skali. Na skali 5 (5 miejsc po przecinku) nie, to nie to samo. ale przy mniejszych dokładnościach dziesiętnych (skala 4 i niższa) są uważane za równe. Dlatego proponuję, aby skala tych dwóch liczb była równa, a następnie je porównać.

Panie Q
źródło
-10

Możesz także porównać z podwójną wartością

BigDecimal a= new BigDecimal("1.1"); BigDecimal b =new BigDecimal("1.1");
System.out.println(a.doubleValue()==b.doubleValue());
Rashmi singh
źródło
5
Prosimy o unikanie tego rozwiązania w miarę możliwości. Nawet pary powinny być porównywane z „epsilon”. Nie ma sensu mieć BigDecimal i porównywać go do podwójnych ... istnieje bardzo duże prawdopodobieństwo, że strzelisz sobie w nogę.
Vadim Kirilchuk,
Podwójne wartości należy porównać za pomocą epsillonów
Bishwajit Purkaystha