Las respuestas existentes realmente no abordaron el lado del hardware de las cosas, así que aquí hay un poco en ese ángulo. La sabiduría convencional es que la multiplicación y la división son mucho más lentas que los cambios, pero la historia real de hoy es más matizada.
Por ejemplo, es cierto que la multiplicación es una operación más compleja de implementar en hardware, pero no siempre termina más lentamente . Como resultado, add
también es significativamente más complejo de implementar que xor
(o en general cualquier operación bit a bit), pero add
(y sub
) generalmente obtienen suficientes transistores dedicados a su operación que terminan siendo tan rápidos como los operadores bit a bit. Por lo tanto, no puede simplemente mirar la complejidad de la implementación de hardware como una guía para la velocidad.
Así que veamos en detalle el desplazamiento frente a los operadores "completos" como la multiplicación y el desplazamiento.
Cambiando
En casi todo el hardware, el cambio en una cantidad constante (es decir, una cantidad que el compilador puede determinar en tiempo de compilación) es rápido . En particular, generalmente sucederá con una latencia de un solo ciclo y con un rendimiento de 1 por ciclo o mejor. En algunos equipos (p. Ej., Algunos chips Intel y ARM), ciertos cambios por una constante pueden incluso ser "gratuitos", ya que pueden integrarse en otra instrucción ( lea
en Intel, las capacidades especiales de cambio de la primera fuente en ARM).
El desplazamiento en una cantidad variable es más un área gris. En hardware antiguo, esto a veces era muy lento y la velocidad cambiaba de generación en generación. Por ejemplo, en el lanzamiento inicial de Intel P4, el cambio en una cantidad variable fue notoriamente lento, ¡lo que requiere un tiempo proporcional a la cantidad de cambio! En esa plataforma, el uso de multiplicaciones para reemplazar los turnos podría ser rentable (es decir, el mundo se ha vuelto al revés). En chips Intel anteriores, así como en generaciones posteriores, el cambio en una cantidad variable no fue tan doloroso.
En los chips Intel actuales, el cambio en una cantidad variable no es particularmente rápido, pero tampoco es terrible. La arquitectura x86 está limitada en lo que respecta a los cambios variables, porque definieron la operación de una manera inusual: las cantidades de cambios de 0 no modifican los indicadores de condición, pero todos los demás cambios sí. Esto inhibe el cambio de nombre eficiente del registro de banderas, ya que no se puede determinar hasta que se ejecute el turno si las instrucciones posteriores deben leer los códigos de condición escritos por el turno, o alguna instrucción previa. Además, los turnos solo escriben en parte del registro de banderas, lo que puede causar un bloqueo parcial de banderas.
El resultado es que en las arquitecturas recientes de Intel, el cambio en una cantidad variable requiere tres "microoperaciones", mientras que la mayoría de las otras operaciones simples (agregar, operaciones bit a bit, incluso multiplicación) solo toman 1. Tales cambios pueden ejecutarse como máximo una vez cada 2 ciclos .
Multiplicación
La tendencia en el hardware moderno de computadoras de escritorio y portátiles es hacer que la multiplicación sea una operación rápida. En los recientes chips Intel y AMD, de hecho, se puede emitir una multiplicación cada ciclo (a esto le llamamos rendimiento recíproco ). La latencia , sin embargo, de una multiplicación es de 3 ciclos. Eso significa que obtienes el resultado de cualquier multiplicación dada 3 ciclos después de comenzar, pero puedes comenzar una nueva multiplicación en cada ciclo. El valor (1 ciclo o 3 ciclos) es más importante depende de la estructura de su algoritmo. Si la multiplicación es parte de una cadena de dependencia crítica, la latencia es importante. De lo contrario, el rendimiento recíproco u otros factores pueden ser más importantes.
La conclusión clave es que en los chips de portátiles modernos (o mejores), la multiplicación es una operación rápida y es probable que sea más rápida que la secuencia de instrucciones 3 o 4 que emitiría un compilador para "obtener el redondeo" correcto para los cambios de fuerza reducida. Para los cambios variables, en Intel, la multiplicación también se preferiría generalmente debido a los problemas mencionados anteriormente.
En plataformas de factor de forma más pequeñas, la multiplicación aún puede ser más lenta, ya que construir un multiplicador completo y rápido de 32 bits o especialmente de 64 bits requiere muchos transistores y potencia. Si alguien puede completar los detalles del rendimiento de la multiplicación en chips móviles recientes, sería muy apreciado.
Dividir
La división es una operación más compleja, en cuanto a hardware, que la multiplicación y también es mucho menos común en el código real, lo que significa que es probable que se le asignen menos recursos. La tendencia en los chips modernos sigue siendo hacia divisores más rápidos, pero incluso los chips modernos de primera línea tardan entre 10 y 40 ciclos en dividirse, y solo están parcialmente canalizados. En general, las divisiones de 64 bits son incluso más lentas que las de 32 bits. A diferencia de la mayoría de las otras operaciones, la división puede tomar un número variable de ciclos dependiendo de los argumentos.
¡Evite las divisiones y reemplácelas con turnos (o deje que el compilador lo haga, pero es posible que deba verificar el ensamblaje) si puede!