2009-11-29 9 views
7

Necesito encontrar la orden más alta 1 en algunos largos, ints y cortos en Java. Por ejemplo, si tuviera un carácter que se parecía al 00110101, necesito un método que arroje 2 (índice del orden más alto 1).Encontrar el orden más alto 1 en una primitiva Java

Ahora, sé que usted puede hacer esto utilizando un bucle como:

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

pero esto es mucho más lento que lo que yo quiero hacer. Sé que las CPU modernas tienen instrucciones que hacen esto en un chip, así que quiero saber cómo puedo hacer una llamada a eso en lugar de tener un bucle explícito.

EDITAR: puntos de bonificación si puede simplemente devolver los índices de todos los que están en la primitiva.

Gracias.

+0

¿Está ejecutando en una máquina endian grande? – int3

+0

Tenía la impresión de que Java manejaba endianess a su manera en la JVM, pero suponiendo que no lo haga, usaré un Intel C2D, tan poco endian. – twolfe18

+0

Ejecutando tu código, obtengo 0, no 2. – Buhb

Respuesta

11

Integer.numberOfLeadingZeros(i) + 1

Ese método utiliza un acercamiento agradable divide y vencerás, copiado aquí para su revisión:

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

El algoritmo es elegante, pero el cambio es horriblemente lento AFAIK. –

+1

Mejor cambiar 8 veces (peor de los casos), que 32, como si se generalizara el ciclo de la pregunta. (Y eso es suponiendo que JIT-Compiler desenrolla el bucle, de lo contrario dominaría la sobrecarga de rama. – meriton

+4

¿Hay alguna referencia para que el cambio sea "terriblemente lento" en Java? Nunca lo escuché. – PSpeed

0

No sé si tocar una instrucción de CPU, pero sé que esto será mucho más rápido si desenrolla el bucle y usa enmascaramiento de bits explícito.

Además, un char no es de 8 bits ... Creo que podría haber significado un byte.

+0

Estaba pensando en C Style Char's (son 8 bits ¿verdad? ...). ¿Los caracteres de Java tienen 2 bytes para soporte Unicode? – twolfe18

+0

Sí, lo son. –

3

La página "Bit Twiddling Hacks" contiene muchos bits de bits. Una es cómo encontrar el index of the highest order bit.

+0

Solía ​​utilizar estos algoritmos en mi código Java, pero la mayoría de ellos se han agregado a la plataforma API en los últimos años. – finnw

+0

Sin embargo, el método de secuencia de Bruijn es aún marginalmente más rápido que el método de división y conquista utilizado en el 'numberOfLeadingZeros' integrado y' numberOfTrailingZeros'. – finnw

0

Por lo que puedo decir, el Pentium y sus amigos no tienen una instrucción preparada para esto. Entonces, lo que hay que hacer es usar un algoritmo decente.

La clave para obtener una respuesta rápida es utilizar una búsqueda binaria. ¿Está buscando un long con 64 bits? 6 comparaciones le darán su bit más alto, todas las veces.

El código se resuelve en un gran árbol feo de 64 sentencias if, pero solo se ejecutará una pequeña parte de ellas, por lo que el tiempo de ejecución es bueno.

Si necesita un código de muestra, puedo hacerlo. Pero prefiero no.

+0

No necesita ser expresado usando un árbol, ver mi respuesta. – meriton

+0

Como ya comenté, me gusta la elegancia del código pero dudo que su rendimiento sea aceptable. –

1

tengo ni idea de si esto es más rápido. Pero no tiene bucle.

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 se compila en bytecode de plataforma independiente, no se puede esperar el soporte para las instrucciones de la CPU. De lo contrario, su código o Integer.highestOneBit() debería ser lo más rápido posible.

+0

bueno, estoy de acuerdo en principio, pero creo que Java hace algunas cosas en formas dependientes de la plataforma (para la eficiencia), pero caen de nuevo en una implementación java si la plataforma no es cooperativa. Esperaba que esta fuera una de ellas ... – twolfe18

+1

Por supuesto, las JVM son específicas de la plataforma, pero para su caso el compilador JIT Debería detectar tu verdadera intención del bytecode, lo que puede ser difícil. Pero si la velocidad es esencial, puede considerar el uso de un ensamblador independiente de la plataforma, es decir, una biblioteca C y JNI. – FelixM

0

¿Es esto algo que estás buscando?

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

:) ... deseo, pero no – twolfe18

+0

jaja - eso es bastante gracioso. Me recuerda a un programador que tuve en el personal una vez que convirtió un número en una cadena para poder rodearlo. Oy. –

Cuestiones relacionadas