2015-06-11 11 views
6

Metoda standardowa Math.sqrt() wydaje się już dość szybka w Javie, ale ma nieodłączną wadę, że zawsze będzie obejmowała operacje 64-bitowe, które nie ograniczają prędkości w przypadku 32-bitowych wartości float. Czy jest to możliwe dzięki niestandardowej metodzie, która jako parametr używa parametru float, wykonuje tylko operacje 32-bitowe i zwraca jako wynik float?Java: 32-bitowa implementacja fp Math.sqrt()

widziałem:

Fast sqrt in Java at the expense of accuracy

i zrobił trochę więcej niż wzmacniać pogląd, że Math.sqrt() jest na ogół trudne do rytmu. Widziałem też:

http://www.codeproject.com/Articles/69941/Best-Square-Root-Method-Algorithm-Function-Precisi

który pokazał mi kilka ciekawych C hacki ++/ASM, że jestem po prostu zbyt nieświadomy do portu bezpośrednio do Java. Chociaż sqrt14 może być interesujący jako część połączenia JNI. . .

Spojrzałem również na Apache Commons FastMath, ale wygląda na to, że biblioteka domyślnie korzysta z standardowego Math.sqrt(), więc nie ma tam pomocy. A wtedy nie Yeppp !:

http://www.yeppp.info/

ale nie przejmowałem się tym jeszcze.

+1

Nie jestem pewien, dostaniesz korzyści prędkości masz nadzieję, że masz –

+1

„operacje 64-bitowe. ... nie robi nic poza zmniejszeniem prędkości w przypadku 32-bitowych wartości zmiennoprzecinkowych "jest błędem. Zasadniczo, operacje zmiennoprzecinkowe są zawsze wykonywane w precyzji FPU, a narzut zwiększa rozszerzalność i zwęża argumenty 'float' do' double', aby dopasować je do FPU. – EJP

+1

@EJP to prawda dla 'sqrtsd' vs' sqrtss', ale oczywiście z perspektywy Java nie można tego kontrolować. Jeśli chodzi o FPU w starym stylu, który działa tak, jak opisujesz, jest w gruncie rzeczy przestarzały (i poważnie ułomny w niektórych Atomach Intel) – harold

Odpowiedz

5

Nie potrzebujesz niczego, aby przyspieszyć sqrt dla wartości 32-bitowych. HotSpot JVM robi to automatycznie dla ciebie.

Kompilator JIT jest wystarczająco inteligentny, aby rozpoznać wzór f2d -> Math.sqrt() -> d2f i zastąpić go szybszą instrukcją procesora sqrtss zamiast sqrtsd. The source.

Benchmark:

@State(Scope.Benchmark) 
public class Sqrt { 
    double d = Math.random(); 
    float f = (float) d; 

    @Benchmark 
    public double sqrtD() { 
     return Math.sqrt(d); 
    } 

    @Benchmark 
    public float sqrtF() { 
     return (float) Math.sqrt(f); 
    } 
} 

A wyniki:

Benchmark Mode Cnt  Score  Error Units 
Sqrt.sqrtD thrpt 5 145501,072 ± 2211,666 ops/ms 
Sqrt.sqrtF thrpt 5 223657,110 ± 2268,735 ops/ms 
+0

Interesujące! Naucz się czegoś nowego każdego dnia. – user3765373

0

Jak wydaje się wiedzieć JNI:

wystarczy napisać minimalny otoki dla double sqrt(double) i float sqrt(float) z math.h i porównanie wydajności c koszulka standardowa biblioteki.

Podpowiedź: nie poczujesz różnicy, chyba że zrobisz wiele kwadratowych korzeni, a wtedy przewaga wydajności polegająca na tym, że instrukcje SIMD wykonają wiele sqrts naraz, najprawdopodobniej zdominuje efekty. Będziesz potrzebował uzyskać tablicę z wartościami zmiennoprzecinkowymi z Java, która może być dość trudna, jeśli używasz standardowych bibliotek Java.