Znalazłem tę java.lang.Integer
implementacjęcompareTo
metody 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, po co używać porównania zamiast odejmowania:
return thisVal - anotherVal;
java
optimization
integer
comparison
integer-overflow
Vladimir
źródło
źródło
Integer.compare(thisVal, anotherVal)
zamiast wypisywać wyrażenie trójskładnikowe.Odpowiedzi:
Wynika to z przepełnienia liczb całkowitych. Gdy
thisVal
jest bardzo duże ianotherVal
jest ujemne, odjęcie tego drugiego od pierwszego daje wynik, który jest większy niż ten,thisVal
który może przelać się do zakresu ujemnego.źródło
thisVal
nie musi być duży.thisVal
może być nawet zero ianotherVal
być,Integer.MIN_VALUE
a już masz przepełnienie. I pamiętaj, że oczywiście może być odwrotnie,thisValue
bardzo mały ianotherVal
raczej duży, aby odległość przekraczałaint
zakres wartości.„Sztuczka” odejmowania polegająca na porównaniu dwóch wartości liczbowych jest zepsuta !!!
int a = -2000000000; int b = 2000000000; System.out.println(a - b); // prints "294967296"
Tutaj
a < b
jednaka - b
jest pozytywne.NIE używaj tego idiomu. To nie działa.
Co więcej, nawet jeśli zadziała , NIE zadziała zapewni żadnej znaczącej poprawy wydajności i może w rzeczywistości kosztować czytelność.
Zobacz też
źródło
((long)a - b)
powinno działać. Chociaż masz rację; bardzo rzadko jest przydatne.((long)a - b)
nie pomaga, ponieważ musisz rzutować wynik z powrotemint
, ponieważ to właśnie musi zwrócić komparator, kończąc ponownie z przepełnieniem. Musiałbyś zrobić coś podobnegoLong.signum
do wyniku, o którym łatwo zapomnieć, jak pokazuje Twój komentarz. I może nie być nawet bardziej wydajne niż toInteger.compare
, z czym JVM mogłaby sobie poradzić…Mówiąc najprościej,
int
typ nie jest wystarczająco duży, aby zapisać różnicę między dwiema dowolnymiint
wartościami. Na przykład różnica między 1,5 miliarda a -1,5 miliarda wynosi 3,0 miliarda, aleint
nie może zawierać wartości większych niż 2,1 miliarda.źródło
Być może ma to na celu uniknięcie przepełnienia / niedomiaru.
źródło
Oprócz przepełnienia należy zauważyć, że wersja z odejmowaniem nie daje takich samych wyników .
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); }
źródło
compareTo
jest wymagane tylko do zwrócenia wartości ujemnej, zerowej lub dodatniej, w zależności od kolejności sortowaniathis
i innego obiektu. Zobacz java.sun.com/j2se/1.5.0/docs/api/java/lang/…