Segunda pregunta primero: div
es una instrucción muy lenta (más de 20 ciclos de reloj). La secuencia anterior consiste en más instrucciones, pero todas son relativamente rápidas, por lo que es una ganancia neta en términos de velocidad.
Las primeras cinco instrucciones (hasta e incluyendo el shrl
) calculan i/10 (explicaré cómo hacerlo en un minuto).
Las siguientes instrucciones vuelven a multiplicar el resultado por 10, pero evitando las instrucciones mul
/imul
(el hecho de que gane o no depende del procesador exacto al que se dirige), los x86 más nuevos tienen multiplicadores muy rápidos, pero los más antiguos no lo haga).
movl %edx, %eax ; eax=i/10
sall $2, %eax ; eax=(i/10)*4
addl %edx, %eax ; eax=(i/10)*4 + (i/10) = (i/10)*5
addl %eax, %eax ; eax=(i/10)*5*2 = (i/10)*10
Esto se resta entonces de i
de nuevo para obtener i - (i/10)*10
que es i % 10
(para números sin signo).
Finalmente, en el cálculo de i/10: La idea básica es reemplazar la división por 10 con la multiplicación por 1/10. El compilador hace una aproximación de punto fijo de esto al multiplicar por (2 ** 35/10 + 1) - ese es el valor mágico cargado en edx
, aunque se emite como un valor firmado a pesar de que en realidad no está firmado, y el desplazamiento a la derecha resultado por 35. Esto resulta para dar el resultado correcto para todos los enteros de 32 bits.
Hay algoritmos para determinar este tipo de aproximación que garantizan que el error es inferior a 1 (que para los enteros significa que es el valor correcto) y GCC, obviamente, utiliza una :) Observación final
: Si desea realidad ver GCC calcular un módulo, hacer que la variable del divisor (por ejemplo, un parámetro de función) por lo que no puede hacer este tipo de optimización. De todos modos, en x86, calcula el módulo usando div
. div
espera que el dividendo de 64 bits en edx:eax
(32 bits en edx, 32 bits en eax - clear edx a cero si está trabajando con un número de 32 bits) y lo divide por el operando que especifique (p. Ej.div ebx
divide edx:eax
por ebx
). Devuelve el cociente en eax
y el resto en edx
. idiv
hace lo mismo para los valores firmados.
¿Está familiarizado con 32 bits? –
https://groups.google.com/forum/#!msg/comp.lang.asm.x86/BPkTrwLEgq8/_LbijZ5QD-cJ –
[División de enteros por constantes] (http://blogs.msdn.com/b/ devdev/archive/2005/12/12/502980.aspx) –