2013-04-20 16 views
8

Chciałbym sposób obliczyć (x + y)/2 dla dowolnych dwóch liczb całkowitych x, y w Javie. W naiwny sposób występują problemy, jeśli x + y> Integer.MAX_VALUE lub < Integer.MIN_VALUE.Znaczenie dwóch int (lub longs) bez przepełnienia, obcięcie w kierunku 0

Guava IntMathuses tej techniki:

public static int mean(int x, int y) { 
    // Efficient method for computing the arithmetic mean. 
    // The alternative (x + y)/2 fails for large values. 
    // The alternative (x + y) >>> 1 fails for negative values. 
    return (x & y) + ((x^y) >> 1); 
    } 

... ale zaokrągla do minus nieskończoności, to znaczy procedura nie zgadza się z naiwnych sposób jak dla wartości {-1, -2} (dając -2, zamiast -1).

Czy istnieje odpowiednia procedura, która skraca się w kierunku 0?

"Po prostu użyj long" nie jest odpowiedź, której szukam, ponieważ chcę metodę, która działa również dla długich danych wejściowych. BigInteger również nie jest odpowiedzią, której szukam. Nie chcę rozwiązania z żadnymi oddziałami.

+0

* „Nie chcę rozwiązanie z wszelkich branż.” * - nawet jeśli branchless najlepszym rozwiązaniem jest wolniejszy niż najlepszego rozwiązania z oddziałów ? –

+2

Oto rozwiązanie dla C++: http://stackoverflow.com/a/3816473/139985. Powinien również działać w Javie. –

+0

Masz rację - jeśli istnieje rozwiązanie z odgałęzieniami, które działa lepiej niż bezlistne na losowym wprowadzaniu, cieszę się, że go używam. Wydaje mi się, że pokazywałem swoje uprzedzenia - wątpię, żeby takie rozwiązanie istniało :) – BeeOnRope

Odpowiedz

2

Musisz dodać 1 do wyniku, jeśli najniższe bity są różne (więc wynik nie jest dokładny i trzeba zaokrąglić), a bit znaku w wyniku jest ustawiony (wynik jest ujemny, więc chcesz zmienić rundę w rundę w górę).

więc następujące powinien zrobić (niesprawdzone):

public static int mean(int x, int y) { 
    int xor = x^y; 
    int roundedDown = (x & y) + (xor >> 1); 
    return roundedDown + (1 & xor & (roundedDown >>> 31)); 
} 
+0

Nie mogłem znaleźć niczego znacznie szybciej. – BeeOnRope

0

Dlaczego nie zrobisz czegoś takiego jak (x-y)/2 + y, który redukuje się do x/2 - y/2 + y = x/2 + y/2? Jeśli więc x+y daje przepełnienie lub niedopełnienie, robisz to w sposób (x-y)/2 + y.

+1

'x - y' może być niedopełnione i jest problematyczne w taki sam sposób jak oryginał. Również gałęzie są bardzo wolne, jeśli są źle przewidywane. – BeeOnRope

+0

Myślę, że jeśli 'x + y' przepełnienia/niedopełnienia,' 'xy' nie może przepełnić/przepełnić ... – Anjoola

+0

Oczywiście, ale to oznacza, że ​​musisz sprawdzić, czy przepełnienie x + y, wprowadzając gałąź, która będzie bardzo słabo przewidywana, jeśli dane wejściowe są losowo rozdzielone (ponieważ wiele kombinacji będzie nad/niedobór). Dlatego powiedziałem "bez oddziałów". – BeeOnRope