Pregunta

Descargo de responsabilidad:No soy un experto en compiladores.Simplemente tengo curiosidad y vengo en busca de iluminación.

He visto a personas afirmar que, por eficiencia, for Los bucles generalmente deben usar una comparación cero para la terminación.Entonces en lugar de:

void blink1(int n) {
    for (int i=0; i<n; i++) {
        blink_led();
    }
}

Deberías escribir:

void blink2(int n) {
    for (int i=n; i>0; i--) {
        blink_led();
    }
}

Pensé que era un poco tonto:¿Por qué poner la carga sobre el ser humano si un compilador puede interpretar ambos casos como "blink_led() n veces"?

Pero usando Señor.Explorador del compilador de Godbolt, ahora creo que estoy equivocado.Para todos los compiladores que probé, la "comparación con cero" siempre produjo un ciclo más corto.Por ejemplo, x86-64 gcc 10.2 con optimización -O3 produjo los siguientes bucles internos:

blink1:
    ...
.L3:
        xor     eax, eax
        add     ebx, 1
        call    blink_led
        cmp     ebp, ebx
        jne     .L3

vs

blink2:
    ...
.L12:
        xor     eax, eax
        call    blink_led
        sub     ebx, 1
        jne     .L12

Entonces aquí está la pregunta

Este parece un caso muy común.

¿Por qué el compilador no puede (o por qué no lo hace) darse cuenta de que el efecto de la for bucle es simplemente "haz esto N veces" - ya sea contando hacia arriba o hacia atrás - ¿y optimizar para eso?

¿Fue útil?

Solución

Lo que lees es una tontería total, excepto por los más primitivos de los compiladores.Primero, la comparación con un entero es tan rápida, posiblemente incluso más rápido que la comparación con una constante.En segundo lugar, un buen compilador de optimización tomará un bucle escrito usando algún patrón común y lo convertirá en el mejor código posible;Puede que no reconozca su patrón ofuscado y producir un código menos bueno para ello.

y, por último, no debe reemplazar legible con un código ilegible a menos que haya una necesidad real para ello.Si pasa una hora haciendo el cambio, debe producir 20 horas ahorró tiempo de CPU al menos.Cuando esté en ese nivel, es muy probable que tengan mejores algoritmos para dar mejores ahorros.

Otros consejos

Creo que estoy de acuerdo principalmente con @ gnasher729, pero aquellas personas lo que la preocupación de la "eficiencia" criticaría el uso de la bucle para el bucle: la variable "I" no agrega nada ...

¿Por qué no:

void blink3(int n) {
    while (n-- > 0) {
       blink_led();
    }
}

He agregado el "> 0" por un par de razones: 1) En caso de que alguien pida una cantidad negativa de parpadeante, no quiera rodar hacia atrás durante 2 mil millones de veces.2) Es un poco más obvio para los unificar (tal vez).

Por cierto, en ejemplo, la función "Blink_Led ()" es raro y pescado, que probablemente espere para poder verlo, luego se apaga.Así que "eficiencia" es un poco fuera de la mesa.

Pero, en general, para la mayoría de las cosas, la eficiencia es principalmente sobre la rapidez con la que se puede codificar y también (más importante) qué tan rápido se entiende.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a cs.stackexchange
scroll top