Pytanie Java Integer compareTo () - dlaczego warto używać porównania a odejmowanie?


Znalazłem to java.lang.Integer Wdrożenie compareTo metoda wygląda następująco:

public int compareTo(Integer anotherInteger) {
    int thisVal = this.value;
    int anotherVal = anotherInteger.value;
    return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));
}

Pytanie brzmi: dlaczego porównywanie zamiast odejmowania:

return thisVal - anotherVal;

76
2018-04-28 10:59


pochodzenie


Kiedy tak szybko martwimy się o mikrooptymalizację, często kończymy z błędnym kodem. - Kevin Bourrillion
Od wersji JDK 7 można go używać Integer.compare(thisVal, anotherVal) zamiast wypisać potrójne wyrażenie. - Stuart Marks


Odpowiedzi:


Jest to spowodowane przepełnieniem liczby całkowitej. Gdy thisVal jest bardzo duży i anotherVal jest ujemny, a następnie odjęcie tego ostatniego od pierwszego daje wynik większy niż thisVal które mogą przepełnić się do ujemnego zakresu.


85
2018-04-28 11:02



Tak, sposób, w jaki zrobili to tutaj, jest prawdopodobnie bardziej skuteczny niż sprawdzenie przepełnienia i innych - rogerdpack
Użyj Guava ComparisonChain. Jest bardzo przydatny! google.github.io/guava/releases/22.0/api/docs/com/google/common/... - Andrea Bergonzo
thisVal nie musi być duży. thisVal może być nawet zero i anotherVal być Integer.MIN_VALUE i już masz przepełnienie. I pamiętaj, że oczywiście może to być na odwrót, thisValue bardzo mały i anotherVal raczej duże, aby mieć odległość, która przelewa się int zakres wartości. - Holger


Odejmowanie "sztuczki" w celu porównania dwóch wartości liczbowych jest zepsute !!!

        int a = -2000000000;
        int b =  2000000000;
        System.out.println(a - b);
        // prints "294967296"

Tutaj, a < b, jeszcze a - b jest pozytywne.

NIE używaj tego idiomu. To nie działa.

Co więcej, nawet jeśli to zadziała, to będzie NIE zapewniają znaczną poprawę wydajności i mogą w rzeczywistości być czytelne pod względem kosztów.

Zobacz też

  • Puzzlers Java Puzzle 65: Dziwna saga podejrzanego sortowania

    Ta łamigłówka ma kilka lekcji. Najbardziej szczegółowe jest: Nie używaj komparatora opartego na odejmowaniu, chyba że masz pewność, że różnica między wartościami nigdy nie będzie większa niż  Integer.MAX_VALUE. Bardziej ogólnie, strzeż się int przelewowy. Kolejną lekcją jest to, że powinieneś unikać "sprytnego" kodu. Staraj się napisać jasny, poprawny kod i nie optymalizuj go, chyba że okaże się to konieczne.


60
2018-04-28 11:09



W rzeczywistości wcale tak nie jest. Jeśli wiesz coś na temat porównywanych liczb, prawdopodobnie będziesz wiedział, że można je bezpiecznie porównać. Nawet nie wiedząc, po prostu ((long)a - b) powinien działać. Chociaż masz rację; bardzo rzadko się przydaje. - amara
@naiad właśnie robi ((long)a - b)nie pomaga, ponieważ musisz oddać wynik z powrotem int, ponieważ to jest to, co komparator musi powrócić, kończąc ponownie z przepełnieniem. Musiałbyś zrobić coś takiego Long.signum na wynik, który łatwo jest zapomnieć, jak pokazuje twój komentarz. I może nie być nawet bardziej wydajne niż Integer.compare, które JVM może obsługiwać wewnętrznie ... - Holger


Mówiąc po prostu, int typ nie jest wystarczająco duży, aby zapisać różnicę między dwoma arbitralnymi int wartości. Na przykład różnica między 1,5 miliarda a -1,5 miliarda to 3,0 miliarda, ale int nie może zawierać wartości większych niż 2,1 miliarda.


9
2018-04-28 12:03





Być może ma to na celu uniknięcie przepełnienia / niedopełnienia.


3
2018-04-28 11:02





Oprócz funkcji przepełnienia należy zwrócić uwagę na wersję z odejmowaniem nie daje takich samych wyników.

  • Pierwsza wersja compareTo zwraca jedną z trzech możliwych wartości: -1, 0 lub 1.
  • Jeśli zastąpisz ostatnią linię odejmowaniem, wynik może być dowolną liczbą całkowitą.

Jeśli wiesz, że nie będzie przepełnienia, możesz użyć czegoś takiego:

public int compareTo(Integer anotherInteger) {
    return sign(this.value - anotherInteger.valuel);
}

1
2018-04-28 13:23



Masz rację, że wyniki nie są takie same. Ale nie muszą być! compareTo jest wymagany tylko do zwracania wartości ujemnej, zerowej lub wartości dodatniej, w zależności od kolejności sortowania this i drugi obiekt. Widzieć java.sun.com/j2se/1.5.0/docs/api/java/lang/... - Christian Semrau