7

Tengo la siguiente pregunta:¿Por qué JDK usa el desplazamiento en lugar de multiplicar/dividir?

Si se le pregunta si usar un cambio frente a un multiplicar o dividir, por ejemplo, la respuesta sería, deje que la JVM optimice.

Ejemplo aquí: is-shifting-bits-faster-than-multiplying

Ahora que estaba buscando en el código fuente del JDK, por ejemplo Priority Queue y el código sólo utiliza el cambio tanto para la multiplicación y división (con y sin signo).

Dando por sentado que la publicación en SO es la respuesta válida, me preguntaba por qué en jdk prefieren hacerlo cambiando de lugar.

¿Se trata de algún detalle sutil no relacionado con el rendimiento? Estoy sospechando que debe tener algo que ver con la multiplicación y división de exceso/defecto, pero no estoy seguro.

Cualquiera tiene una idea? ¿Los problemas sutiles de desbordamiento se manejan mejor usando el cambio? ¿O es solo una cuestión de gusto?

Respuesta

6

Creo que lo hacen en este ejemplo específico para usar el bit de signo. Java carece de tipos sin signo, por lo que no es posible emular a >>> 1 con a /= 2 para los números que utilizan el bit más significativo. Tenga en cuenta que el código solo usa >>> en su ejemplo. Estoy razonablemente seguro de que se trata de obtener un uso completo de todo el rango de bits.

+0

Así que no es posible escribir código libre de errores sin operador de turno para sutil problemas como este? – Cratylus

+0

@ user384706 Por supuesto que puedes: un simple operador ternario aquí y allá podría ayudarte a hacer el truco. Sin embargo, la eficiencia va a sufrir. – dasblinkenlight

+0

¿Sería posible mostrar un ejemplo de esto? Me interesaría saber – Cratylus

2

Es más una cuestión de gusto. Algunas personas están tan acostumbradas a las operaciones binarias que son más nativas de ellas (personalmente también las uso en el código que estoy escribiendo para mí). Sin embargo, desde el punto de vista del rendimiento, los dos se comportan igual (la optimización ocurre en tiempo de compilación, por lo que el uso de turnos mejorará el tiempo de compilación, pero con una fracción menor y puedes descuidar eso).

EDIT Y como suele suceder, siempre hay algo nuevo que aprendo en cada respuesta que doy: considere this. Esto demuestra por qué la división por dos no siempre se puede optimizar para cambiar. Entonces mi comentario anterior es casi completamente erróneo, siempre y cuando java no tenga tipos sin firmar.

+1

De manera más general: el JIT en java solo puede reemplazar la división por una potencia de 2 con cambios si puede garantizar que los números sean positivos.Si no, necesitamos una rutina más compleja (que básicamente se reduce a 3 turnos y un complemento para la versión libre de sucursal, o una sucursal y agregar + turno) – Voo

3

Algunas razones válidas para preferir el cambio en Java:

  • Si hay una posibilidad de que pueda estar ejecutando en un entorno no optimizado y no se puede garantizar que el compilador JIT hará que la optimización necesaria para usted. Esto es probablemente raro hoy en día, pero aún podría suceder en algunas circunstancias.
  • Si está realmente haciendo manipulaciones de bits lugar de operaciones numéricas - es más claro en el código fuente para utilizar los cambios directamente
  • Si desea operaciones sin firmar (por ejemplo, usted puede fácilmente hacer cambios sin firmar, pero no sin dividir)
+0

Supongo que la razón 3 es por qué, por ejemplo, en la implementación de Priority Queue prefieren el cambio? – Cratylus

5

Además de que el cambio es más rápido que la división en la mayoría de los sistemas. El >>> realiza una operación sin firmar, y dicha división no. p.ej. si quiere el punto medio de dos valores, necesita usar >>> para evitar un desbordamiento. (Consulte Arrays.binarySearch para obtener un código similar)

+0

Me preguntaba por qué mencionas el rendimiento en tu primera oración. ¿No lo optimiza JVM de todos modos? Esto es lo que entiendo del otro SO que menciono en OP – Cratylus

+1

La división no es equivalente a cambiar si las entradas son negativas, y la JVM no siempre puede probar que las entradas son no negativas, en cuyo caso tiene que recibir el golpe de división. –

+0

@LouisWasserman: ¿Entonces usted dice que siempre debemos usar operadores de turno porque JVM no siempre optimiza como esperamos? En el subproceso de SO al que me he vinculado, esto no se mencionó Creo que – Cratylus

Cuestiones relacionadas