La tarea es simple: escribir ensamblaje que calcule el orden de magnitud de un número entero utilizando la menor cantidad de ciclos de reloj posible.
- El orden de magnitud se define como
log10
, nolog2
. - El rango de entrada válida es
0
a , inclusive. El comportamiento para la entrada fuera de ese rango no está definido.1012
- Los valores deben redondearse al entero más cercano, con la excepción de que, dada la entrada,
0
la salida debe ser0
. (Puede considerar que esta es la mejor representación del infinito negativo que es posible en enteros sin signo). - Debe ser x86 ensamblado.
- El entero debe ser un valor de tiempo de ejecución , no un entero estático / en línea. Entonces no sabemos qué es en tiempo de compilación.
- Suponga que ya tiene un entero cargado en un registro. (Pero incluya establecer el valor en el registro en la respuesta para mayor claridad).
- No se pueden llamar a bibliotecas o funciones externas.
- Libre de usar cualquiera de las instrucciones disponibles en los documentos de Intel .
- No C.
- Cualquiera de las ~ 7 arquitecturas Intel Core son aceptables (enumeradas en la página 10 ). Idealmente Nehalem (Intel Core i7).
La respuesta ganadora es aquella que utiliza la menor cantidad de ciclos de reloj posibles. Es decir, puede tener la mayoría de las operaciones por segundo. Los resúmenes aproximados del ciclo del reloj están aquí: http://www.agner.org/optimize/instruction_tables.pdf . El cálculo de los ciclos de reloj puede ocurrir después de que se publique la respuesta.
math
fastest-algorithm
assembly
Lance Pollard
fuente
fuente
Respuestas:
7 ciclos, tiempo constante
Aquí hay una solución basada en mi respuesta a esta pregunta SO . Utiliza BSR para contar cuántos bits se necesitan para contener el número. Busca cuántos dígitos decimales se necesitan para representar el número más grande que pueden contener muchos bits. Luego resta 1 si el número real es menor que la potencia más cercana de 10 con esa cantidad de dígitos.
Compila en GCC 4.6.3 para ubuntu y devuelve el valor en el código de salida.
No estoy seguro de interpretar esa tabla de ciclos para cualquier procesador moderno, pero usando el método @ DigitalTrauma, en el procesador Nehalim, obtengo 7 ?
fuente
The integer must be a runtime value, not a static/inline integer. So we don't know what it is at compile time.
Mejor caso 8 ciclos, peor caso 12 ciclos
Como no está claro en la pregunta, estoy basando esto en las latencias de Ivy Bridge.
El enfoque aquí es utilizar la
bsr
instrucción (escaneo de bits inverso) como log2 () de un hombre pobre. El resultado se usa como índice en una tabla de salto que contiene entradas para los bits 0 a 42. Supongo que dado que la operación en datos de 64 bits es implícitamente requerida, entonces el uso de labsr
instrucción está bien.En el mejor de los casos, la entrada jumptable puede asignar el
bsr
resultado directamente a la magnitud. Por ejemplo, para entradas en el rango 32-63, elbsr
resultado será 5, que se asigna a una magnitud de 1. En este caso, la ruta de instrucciones es:En el peor de los casos, el
bsr
resultado se correlacionará con dos posibles magnitudes, por lo que la entrada de la tabla de salto hace uno adicionalcmp
para verificar si la entrada es> 10 n . Por ejemplo, para las entradas en el rango 64-127, elbsr
resultado será 6. La entrada correspondiente de la tabla de salto verifica si la entrada> 100 y establece la magnitud de salida en consecuencia.Además de la ruta del peor de los casos, tenemos una instrucción mov adicional para cargar un valor inmediato de 64 bits para usar en
cmp
, por lo que la ruta de la instrucción del peor caso es:Aquí está el código:
Esto se generó principalmente a partir de la salida del ensamblador gcc para el código C de prueba de concepto que escribí . Tenga en cuenta que el código C usa un goto computable para implementar la tabla de salto. También utiliza el
__builtin_clzll()
gcc incorporado, que compila lasbsr
instrucciones (más unxor
).Consideré varias soluciones antes de llegar a esta:
FYL2X
para calcular el registro natural, luegoFMUL
por la constante necesaria. Esto presumiblemente ganaría esto si fuera un concurso [tag: instrucción: golf]. PeroFYL2X
tiene una latencia de 90-106 para el puente Ivy.Búsqueda binaria codificada. En realidad, esto puede ser competitivo: dejaré que alguien más lo implemente :).
Tabla de búsqueda completa de resultados. Estoy seguro de que esto es teóricamente más rápido, pero requeriría una tabla de búsqueda de 1TB, aún no práctica, tal vez en unos pocos años si la Ley de Moore continúa vigente.
fuente
jmp
yjcc
no tienen latencia, solo costos de rendimiento. La predicción de rama + ejecución especulativa significa que las dependencias de control no son parte de las cadenas de dependencia de datos.