2011-12-03 9 views
5

Wystarczy, aby wyjaśnić to nie jest kwestia pracy domowej, jak widziałem podobnych oskarżeń wobec innych pytań bitowych-hackish:Czy procesowanie 5-Op Log2 (Int 32) może być wykonane w Javie?

Powiedział, że mam ten bit włamać się w katalogu C:

#include <stdio.h> 

const int __FLOAT_WORD_ORDER = 0; 
const int __LITTLE_END = 0; 

// Finds log-base 2 of 32-bit integer 
int log2hack(int v) 
{ 
    union { unsigned int u[2]; double d; } t; // temp 
    t.u[0]=0; 
    t.u[1]=0; 
    t.d=0.0; 

    t.u[__FLOAT_WORD_ORDER==__LITTLE_END] = 0x43300000; 
    t.u[__FLOAT_WORD_ORDER!=__LITTLE_END] = v; 
    t.d -= 4503599627370496.0; 
    return (t.u[__FLOAT_WORD_ORDER==__LITTLE_END] >> 20) - 0x3FF; 
} 

int main() 
{ 
    int i = 25; //Log2n(25) = 4 
    int j = 33; //Log2n(33) = 5 

    printf("Log2n(25)=%i!\n", 
     log2hack(25)); 
    printf("Log2n(33)=%i!\n", 
     log2hack(33)); 

    return 0; 
} 

chcę przekonwertować to na Javę. Do tej pory co mam to:

public int log2Hack(int n) 
    { 
     int r; // result of log_2(v) goes here 
     int[] u = new int [2]; 
     double d = 0.0; 
     if (BitonicSorterForArbitraryN.__FLOAT_WORD_ORDER== 
       BitonicSorterForArbitraryN.LITTLE_ENDIAN) 
     { 
      u[1] = 0x43300000; 
      u[0] = n; 
     } 
     else  
     { 
      u[0] = 0x43300000; 
      u[1] = n; 
     } 
     d -= 4503599627370496.0; 
     if (BitonicSorterForArbitraryN.__FLOAT_WORD_ORDER== 
       BitonicSorterForArbitraryN.LITTLE_ENDIAN) 
      r = (u[1] >> 20) - 0x3FF; 
     else 
      r = (u[0] >> 20) - 0x3FF; 

     return r; 
    } 

(Uwaga to wewnątrz bitonic klasy sortowni kopalni ...)

Tak czy inaczej, kiedy biegnę to dla tych samych wartości 33 i 25, mam 52 w w każdym przypadku.

Wiem, że liczby całkowite Java są podpisane, więc jestem prawie pewien, że ma to coś wspólnego z tym, dlaczego to się nie udaje. Czy ktoś ma jakieś pomysły, w jaki sposób mogę uzyskać ten 5-op, 32-bitowy dziennik 2 do pracy w Javie?

P.S. Dla przypomnienia, technika nie jest moja, pożyczałem ją stąd: http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogIEEE64Float

+2

Korekta: liczby całkowite Java są podpisane. W rzeczywistości każdy podstawowy typ danych z wyjątkiem 'char' jest podpisany. –

+0

Użyj ">>>", aby uzyskać logiczną prawą zmianę, która nie powtarza znaku. – fuz

+0

Przepraszam Sanjay, to jest to, co chciałem powiedzieć (że są podpisane) .... Zmieniam tekst ... –

Odpowiedz

5

Jeśli pracujesz w Javie, nie możesz po prostu wykonać 31 - Integer(v).numberOfLeadingZeros()? Jeśli implementują to przy użyciu __builtin_clz, powinno być szybkie.

+0

Nice !! Świetny pomysł, nie czytałem o tej funkcji ... Zasadniczo uczę się języka Java, czytałem dokumenty dla początkujących Oracle itp., Ale wciąż nie wiem, co to jest. –

0

Myślę, że nie rozumiesz znaczenia tego kodu. Kod C używa związku - struktury, która odwzorowuje tę samą pamięć na dwa lub więcej różnych pól. To umożliwia dostęp do pamięci przydzielonej dla podwójnego jako liczby całkowite. W kodzie Java nie używa się unii, ale dwie różne zmienne, które są mapowane na różne części pamięci. To powoduje, że haker nie działa.

W związku z tym, że Java nie ma żadnych związków, należy użyć serializacji, aby uzyskać pożądane rezultaty. Ponieważ jest to dość powolne, dlaczego nie użyć innej metody do obliczenia logarytmu?

+0

Wszelkie sugestie inne niż tabela odnośników dla niższej op alternatywy dla po prostu bit przesunięcia mojej wartości (oczywista i łatwa naprawa)? –

+0

@Jason Na stronie, którą połączyłeś, istnieją inne podejścia, które można rozważyć. Ale jaki jest problem z podejściem do tablicy odnośników na tej stronie, którą połączyłeś? – fuz

+0

Jedyną inną wymienioną metodą była metoda z przesunięciem, która choć nieco szybsza niż metoda tradycyjna była znacznie wolniejsza niż inne metody hackowania bitów, w tym tabela. Tabela odnośników jest w porządku (7 operacji dla 32-bitowych), ale zastanawiałem się, czy ktoś nie widział żadnych innych szybszych nowatorskich haseł Java log2, np. jak inne 5 op jeden ... –

0

Używasz tego związku do przekształcenia pary intów w podwójny o tym samym wzorze bitowym. W języku Java można to zrobić za pomocą Double.longBitsToDouble, a następnie przekonwertować ponownie za pomocą Double.doubleToLongBits. Java zawsze (lub przynajmniej sprawia wrażenie, że zawsze jest) big-endian, więc nie potrzebujesz kontroli endianness.

Powiedział, że moja próba dostosowania kodu do Java nie działa. Sygnatura liczb całkowitych Java może stanowić problem.

Powiązane problemy