Jeśli JVM tego nie robi, możesz to zrobić samodzielnie.
Jak wspomniano, prawe przesunięcia na liczbach ujemnych nie zachowują się tak samo jak podział, ponieważ wynik jest zaokrąglany w niewłaściwym kierunku. Jeśli wiesz, że dywidenda jest nieujemna, możesz bezpiecznie zastąpić dywizję zmianą. Jeśli może być ujemna, możesz skorzystać z poniższej techniki.
Jeśli można wyrazić swój oryginalny kod w tej formie:
int result = x/(1 << shift);
można zastąpić go z tego kodu zoptymalizowanego:
int result = (x + (x >> 31 >>> (32 - shift))) >> shift;
Lub alternatywnie:
int result = (x + ((x >> 31) & ((1 << shift) - 1))) >> shift;
These formuły kompensują niepoprawne zaokrąglenia, dodając małą liczbę obliczoną z bitu znaku z dywidendy. Działa to na każdym x
z wszystkich wartości przesunięcia od 1 do 30.
Jeśli przesunięcie to 1 (to znaczy, to jest dzielenie przez 2), a następnie >> 31
można usuwać w pierwszej formuły, aby ten bardzo czyste fragmentu:
int result = (x + (x >>> 31)) >> 1;
Zauważyłem, że te techniki są szybsze, nawet jeśli przesunięcie nie jest stałe, ale oczywiście przynoszą one najwięcej korzyści, jeśli przesunięcie jest stałe. Uwaga: W przypadku long
x
zamiast int
, zmiany 31 i 32 odpowiednio do 63 i 64.
Examining the generated machine code pokazuje, że (nic dziwnego) HotSpot VM Server może zrobić optymalizacji automatycznie, gdy zmiana jest stała, ale (również zaskoczeniem) Maszyna wirtualna klienta HotSpot jest zbyt głupia.
Czy spojrzałeś na kod bajtowy wygenerowany przez te dwie instrukcje? – Julien
Zauważ, że istnieje kilka kompilatorów. E.g javac i ten w czasie zaćmienia. –
@Julien Rozważam także JIT. – wchargin