¿Hay ejemplos de chips donde comparar 2 con cero sería más lento que comparar 1 con cero?

0

Esta pregunta en StackOverflow es como esta que es más rápida: while(1) o while(2) ? Preguntar cuál de los dos bucles infinitos es más rápido solo tiene sentido si lo preguntas en el sentido "lo que puede hacer más iteraciones por segundo".

Las respuestas serias hasta ahora no son "ninguna diferencia".

Ahora suponga que un compilador es lo suficientemente tonto y genera una instrucción de comparación, por lo que el código compara 1 contra cero en el primer bucle y 2 contra cero en el segundo bucle.

Algo como esto para el primer bucle:

start:
    mov reg1, 1
    cmp reg1, 0
    je start

y algo como esto para el segundo bucle:

start:
    mov reg1, 2
    cmp reg1, 0
    je start

Esto se ejecuta con la misma rapidez en algunos chips potentes como Intel Core i5 porque toda la comparación se realiza en hardware y efectivamente solo compara dos números enteros de 32 bits (o 64 bits) en una sola operación, por lo que cualquier comparación de este tipo toma el mismo tiempo.

¿Qué pasa con algunos chips muy simples de muy baja potencia? Supongo que los circuitos de comparación en ellos podrían diseñarse simplificados para ser más pequeños a expensas de la velocidad.

¿Comparando 2 contra cero tomaría el mismo tiempo que comparando 1 contra cero en cualquier chip razonable?

    
pregunta sharptooth

3 respuestas

2

Primero tienes que preguntarte qué significa realmente while(1) o while(2) .

  

Ahora suponga que un compilador es lo suficientemente tonto y genera una instrucción de comparación, por lo que el código compara 1 contra cero en el primer bucle y 2 contra cero en el segundo bucle.

Entonces, tu compilador hipotético está básicamente expandiéndolos para que sean while(1 != 0) y while(2 != 0) , cuyos resultados serían un 1 (verdadero), o un 0 (falso). ¿Este compilador tonto también va a comparar aquellos con 0, y si es así, qué va a hacer con los resultados de esa comparación? Veo un problema de recursión infinita pasando por allí.

Sin embargo, dejando eso a un lado, y asumimos que solo hace una comparación y toma el resultado de esa comparación como un valor lógico de sí / no, ¿cómo esperaría que el compilador implementara eso como lenguaje ensamblador? Bueno, obviamente eso depende de la arquitectura. Si tienes un operador de comparación entonces obviamente debería usar eso. Algo así como, en pseudo-montaje:

_while:
    ld r0, 1
    ld r1, 0
    cmp r0, r1
    beq _while_finished // jump if the compare was equal
    // ... loop code in here
    bra _while
_while_finished:
    // ... continue with the code.

Reemplazar el 1 por un 2 dejaría el mismo número de instrucciones.

Pocos microcontroladores pequeños tienen un cmp o similar, por lo que la forma más común es restar un valor de otro y probar si el resultado es cero. Por ejemplo:

_while:
    ld r0, 1
    ld r1, 0
    sub r0, r0, r1 // Subtract r1 from r0 and leave the result in r0
    beqz _while_finished // Branch if zero flag set by last math operation
    // ... loop code in here
    bra _while
_while_finished:
    // ... continue with the code.

De nuevo, sustituir el 1 con un 2 dejaría el mismo número de instrucciones. Entonces, debes preguntarte ahora, con ese código, ¿qué parte podría llevar más tiempo con un 2 que con un 1? Solo la instrucción sub tiene el potencial para hacer eso, y solo si el diseño del chip es increíblemente pobre. Normalmente, la instrucción ALU realiza una instrucción sub o add como una sola operación, y los valores involucrados no tienen relación con el tiempo empleado. Solo si la ALU realiza un sub a, b, c cargando primero a con b y luego disminuyéndolo c veces, tendría alguna posibilidad de que los números involucrados tuvieran alguna relación con el tiempo tomado, y nunca he venido a través de una forma tan primitiva de hacerlo. A menos que, por supuesto, el chip haya sido diseñado por la misma persona que diseñó el compilador;)

Entonces la respuesta es:

En cualquier sistema normal, no, los operandos de la comparación no tendrían relación con el tiempo necesario para realizar la comparación.

    
respondido por el Majenko
1

En la mayoría de las computadoras modernas, el compilador (y en realidad es el enlazador que genera el código de la máquina, aunque con LLVM no estoy seguro) terminará probando la condición para ver si es cero. Otras respuestas asumen que hay una resta o una comparación con dos registros, la mayoría de los compiladores de optimización no lo harán.

Valor de recuento de carga

Load "count value" -> Register
Brz  pointer to next block of code    ; Branch if zero
Bra  pointer back to top of loop      ; else

Este código es idéntico para cada una de sus opciones, por lo tanto, los bucles son idénticos.

Pero si miras el código, la mayoría de los compiladores saben que "2" y "1" no son variables y ni siquiera le asignarán memoria. Solo producirán

Bra  pointer back to top of loop      ; branch always

para ambos escenarios.

    
respondido por el placeholder
0

Si puedes encontrar un compilador que sea lo suficientemente estúpido como para no optimizar este caso, haría la comparación en tiempo de ejecución mientras (2! = 0) o mientras (1! = 0). En C, esto es, por definición, una comparación entre dos valores int, que tienen un tamaño mínimo de 16 bits. Por lo tanto, en el tiempo de ejecución (al menos) se deben comparar 16 bits, utilizando las instrucciones apropiadas en la máquina de destino. No importa si el valor en uno de los valores int es 1 o 2.

El tipo de pregunta asume que un compilador podría optimizar de alguna manera el hecho de que 1 puede representarse en 1 bit, mientras que 2 requiere 2 bits, pero al mismo tiempo NO hacer el plegado constante que elimina la comparación por completo. En mi opinión, esto es tan extraño que tal compilador podría generar un código adicional para el caso while (1). La parte superior del caso hace que este caso sea más grande que el caso while (2).

    
respondido por el Wouter van Ooijen

Lea otras preguntas en las etiquetas