2009-11-29 11 views
7

Ho bisogno di trovare l'ordine più alto 1 in alcuni long, ints e short in Java. Ad esempio, se avessi un carattere simile a 00110101, ho bisogno di un metodo che restituirà 2 (indice del più alto ordine 1).Trovare l'ordine più alto 1 in un primitivo Java

Ora, so che si può fare questo usando un ciclo for come:

for(int i=0; i<8; i++) 
    if((x & 1<<i) != 0) return i; 
return -1; 

, ma questo è il modo più lento di quello che voglio fare. So che le moderne CPU hanno istruzioni che lo fanno su chip, quindi voglio sapere come posso effettuare una chiamata a questo piuttosto che avere un ciclo esplicito.

MODIFICA: punti bonus se è possibile restituire gli indici di tutti quelli nella primitiva.

Grazie.

+0

Sei in esecuzione su una macchina big endian? – int3

+0

Avevo l'impressione che Java gestisse le endianess a modo suo nella JVM, ma supponendo che non funzionasse, userò un Intel C2D, così poco endian. – twolfe18

+0

Eseguendo il codice, ottengo 0, non 2. – Buhb

risposta

11

Integer.numberOfLeadingZeros(i) + 1

Questo metodo utilizza un bel approccio divide et impera, copiato qui per la tua opinione:

public static int numberOfLeadingZeros(int i) { 
    // HD, Figure 5-6 
    if (i == 0) 
     return 32; 
    int n = 1; 
    if (i >>> 16 == 0) { n += 16; i <<= 16; } 
    if (i >>> 24 == 0) { n += 8; i <<= 8; } 
    if (i >>> 28 == 0) { n += 4; i <<= 4; } 
    if (i >>> 30 == 0) { n += 2; i <<= 2; } 
    n -= i >>> 31; 
    return n; 
} 
+0

L'algoritmo è elegante, ma lo spostamento è orribilmente lento AFAIK. –

+1

Meglio spostare 8 volte (caso peggiore) di 32, come farebbe la generalizzazione del ciclo dalla domanda. (E ciò presuppone che il compilatore JIT srotoli il ciclo, altrimenti dominerebbe il ramo in testa – meriton

+4

C'è un riferimento per lo spostamento che è "orribilmente lento" in Java? Non l'ho mai sentito. – PSpeed

0

Non so se si preme un'istruzione della CPU, ma so che sarà molto più veloce se si srotola il ciclo e si utilizza il mascheramento di bit esplicito.

Inoltre, un char non è 8 bit ... Penso che potresti aver inteso un byte.

+0

Stavo pensando allo stile C di char (sono 8 bit giusto? ...). I caratteri Java sono 2 byte per il supporto Unicode? – twolfe18

+0

Sì, lo sono. –

3

La pagina "Bit Twiddling Hacks" contiene molti hack di bit. Uno è come trovare il index of the highest order bit.

+0

Ho usato questi algoritmi nel mio codice Java, ma la maggior parte di essi sono stati aggiunti all'API della piattaforma negli ultimi anni. – finnw

+0

Tuttavia, il metodo di sequenza de Bruijn è ancora marginalmente più veloce del metodo dividi-conquista utilizzato nel 'built-in numberOfLeadingZeros' e' numberOfTrailingZeros'. – finnw

0

Per quanto posso dire, il Pentium e gli amici non hanno un'istruzione già pronta per questo. Quindi la cosa da fare è usare un algoritmo decente.

La chiave per ottenere rapidamente la risposta è utilizzare una ricerca binaria. Stai guardando un long con 64 bit? 6 confronti ti daranno il tuo bit più alto, ogni volta.

Il codice funziona su un grosso albero brutto di 64 se istruzioni, ma solo una frazione di quelle verrà mai eseguita, quindi il runtime è buono.

Se è necessario codice di esempio, posso farlo. Ma preferirei di no.

+0

Non è necessario che sia espresso usando un albero, vedi la mia risposta. – meriton

+0

Come ho commentato, mi piace l'eleganza del codice, ma dubito che le sue prestazioni siano accettabili. –

1

Non ho idea se questo è più veloce. Ma non ha loop.

if(i==0) return -1; 

highest=0; 
if (i & 0xffff0000) 
{ 
    highest+=16; 
    i>>=16; 
} 
if (i & 0xff00) 
{ 
    highest+=8; 
    i>>=8; 
} 
if (i & 0xf0) 
{ 
    highest+=4; 
    i>>=4; 
} 
if (i & 0xC) 
{ 
    highest+=2; 
    i>>=2; 
} 
if (i & 0x2) 
{ 
    highest+=1; 
} 

return highest; 
0

Java viene compilato in bytecode indipendente dalla piattaforma, non si può pretendere il supporto per le istruzioni della CPU. Altrimenti il ​​tuo codice o Integer.highestOneBit() dovrebbe essere il più veloce possibile.

+0

beh, sono d'accordo in linea di principio, ma penso che java faccia alcune cose in modi dipendenti dalla piattaforma (per l'efficienza), ma cadono torna su un'implementazione java se la piattaforma non è cooperativa, speravo che fosse uno di questi ... – twolfe18

+1

Ovviamente le JVM sono specifiche della piattaforma, ma per il tuo caso il compilatore JIT è wou Devo rilevare la tua vera intenzione dal bytecode, che può essere difficile. Ma se la velocità è essenziale, si potrebbe prendere in considerazione l'utilizzo di un assemblatore indipendente dalla piattaforma, cioè una libreria C e JNI. – FelixM

0

E 'qualcosa del genere che cerchi?

System.out.println("00110101".indexOf("1")); 
+0

:) ... lo vorrei, ma no – twolfe18

+0

haha ​​- è piuttosto divertente. Mi ricorda un programmatore che ho avuto sul personale una volta che ha convertito un numero in una stringa in modo da poterlo arrotondare. Oy. –

Problemi correlati