Domanda

Disclaimer: non sono un esperto di compilatore. Sono semplicemente curioso e vieni alla ricerca dell'illuminazione.

Ho visto le persone affermano che - per efficienza - i loops for dovrebbero generalmente utilizzare un confronto zero per la risoluzione. Così piuttosto che:

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

Dovresti scrivere:

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

Ho pensato che fosse un po 'sciocco: perché mettere il peso sull'umano se un compilatore potrebbe interpretare entrambi i casi come "blink_led () n volte"?

Ma usando Mr. Il compilatore di Godbolt Explorer , ora penso che mi sbaglio. Per tutti i compilatori ho provato, il "confronto contro lo zero" ha sempre prodotto un ciclo più breve. Ad esempio, X86-64 GCC 10.2 con -O3 ottimizzazione ha prodotto i seguenti anelli interni:

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
.

Quindi ecco la domanda

Questo sembra un caso così comune.

Perché non è possibile (o perché non) il compilatore si nota che l'effetto del ciclo for è semplicemente "fare questa cosa n volte" - se contare o contare giù - e ottimizzare per questo?

È stato utile?

Soluzione

Quello che leggi è totale assurdità, ad eccezione del più primitivo dei compilatori.Innanzitutto, il confronto con un intero è veloce, forse anche più veloce del confronto con una costante.In secondo luogo, un buon compilatore ottimizzante prenderà un ciclo scritto usando un modello comune e trasformerlo nel miglior codice possibile;Potrebbe non riconoscere il tuo modello offuscato e produrre un codice meno buono per questo.

E infine, non dovresti sostituire leggibile con codice illeggibile a meno che non ci sia un bisogno effettivo per questo.Se trascorri un'ora di modifica, ha bisogno di produrre almeno 20 ore di tempo di CPU salvato.Quando sei a quel livello, è molto probabile che gli algoritmi migliori danno migliori risparmi.

Altri suggerimenti

Penso di essere d'accordo per lo più con @ Gnasher729, ma quelle persone di ciò che preoccuparsi di "efficienza" criticano usando il ciclo per il ciclo affatto - la variabile "I" non aggiunge nulla ...

Perché non:

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

Ho aggiunto il "> 0" per un paio di motivi: 1) Nel caso in cui qualcuno richieda una quantità negativa di lampeggiare, non voglio rotolare all'indietro per 2 miliardi di volte.2) È un po 'più ovvio per l'unitario (forse).

A proposito, in Esempio intrecciato, la funzione "BLACK_LED ()" è strana e fishy - probabilmente aspettare per essere in grado di vederlo andare avanti, poi spento.Quindi "efficienza" è un po 'fuori dal tavolo.

Ma, in generale, per la maggior parte delle cose, l'efficienza è per lo più su quanto velocemente può essere codificato e anche (cosa più importante) quanto velocemente è compreso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a cs.stackexchange
scroll top