Di recente stavo lavorando a un progetto personale quando mi sono imbattuto in uno strano problema.
In un ciclo molto stretto ho un numero intero con un valore compreso tra 0 e 15. Ho bisogno di ottenere -1 per i valori 0, 1, 8 e 9 e 1 per i valori 4, 5, 12 e 13.
Mi sono rivolto a godbolt per verificare alcune opzioni e sono rimasto sorpreso dal fatto che sembrava che il compilatore non potesse ottimizzare un'istruzione switch allo stesso modo di una catena if.
Il link è qui: https://godbolt.org/z/WYVBFl
Il codice è:
const int lookup[16] = {-1, -1, 0, 0, 1, 1, 0, 0, -1, -1, 0, 0, 1, 1, 0, 0};
int a(int num) {
return lookup[num & 0xF];
}
int b(int num) {
num &= 0xF;
if (num == 0 || num == 1 || num == 8 || num == 9)
return -1;
if (num == 4 || num == 5 || num == 12 || num == 13)
return 1;
return 0;
}
int c(int num) {
num &= 0xF;
switch (num) {
case 0: case 1: case 8: case 9:
return -1;
case 4: case 5: case 12: case 13:
return 1;
default:
return 0;
}
}
Avrei pensato che bec avrebbe prodotto gli stessi risultati, e speravo di poter leggere da solo i bit-hack per realizzare un'implementazione efficiente poiché la mia soluzione (la dichiarazione switch - in un'altra forma) era piuttosto lenta.
Stranamente, b
compilato per bit-hack mentre c
era praticamente non ottimizzato o ridotto in un caso diverso a a
seconda dell'hardware di destinazione.
Qualcuno può spiegare perché c'è questa discrepanza? Qual è il modo "corretto" per ottimizzare questa query?
MODIFICARE:
Una precisazione
Voglio che la soluzione switch sia la soluzione più veloce o allo stesso modo "pulita". Tuttavia, quando compilato con ottimizzazioni sulla mia macchina, la soluzione if è significativamente più veloce.
Ho scritto un programma rapido per dimostrare e TIO ha gli stessi risultati che trovo localmente: provalo online!
Con static inline
la tabella di ricerca si accelera un po ': provalo online!
if
batte ancora switch
(la ricerca stranamente diventa ancora più veloce) [TIO da seguire]
-O3
e ha compilatoc
qualcosa di probabilmente peggiore dia
ob
(c
aveva due salti condizionali più alcune manipolazioni di bit, contro solo un salto condizionale e una manipolazione di bit più semplice perb
), ma comunque meglio di un oggetto ingenuo per test articolo. Non sono sicuro di cosa tu stia davvero chiedendo qui; il semplice fatto è che un compilatore ottimizzante può trasformare uno di questi in uno qualsiasi degli altri, se lo desidera, e non ci sono regole rigide e veloci per ciò che farà o non farà.