Ostatnio pracowałem nad osobistym projektem, kiedy natknąłem się na dziwny problem.
W bardzo ciasnej pętli mam liczbę całkowitą o wartości od 0 do 15. Muszę uzyskać -1 dla wartości 0, 1, 8 oraz 9 i 1 dla wartości 4, 5, 12 i 13.
Zwróciłem się do Godbolta, aby sprawdzić kilka opcji i byłem zaskoczony, że wydawało się, że kompilator nie może zoptymalizować instrukcji switch w taki sam sposób jak łańcuch if.
Link jest tutaj: https://godbolt.org/z/WYVBFl
Kod to:
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;
}
}
Myślałem, że b i c przyniosą takie same wyniki, i miałem nadzieję, że sam potrafię odczytać hacki bitów, aby samemu wymyślić wydajną implementację, ponieważ moje rozwiązanie (instrukcja switch - w innej formie) było dość wolne.
Dziwnie, b
skompilowany do hacków bitowych, podczas gdy c
był albo prawie niezoptymalizowany, albo zredukowany do innego przypadku a
uzależnienia od docelowego sprzętu.
Czy ktoś może wyjaśnić, dlaczego istnieje taka rozbieżność? Jaki jest „prawidłowy” sposób optymalizacji tego zapytania?
EDYTOWAĆ:
Wyjaśnienie
Chcę, aby rozwiązanie przełącznika było najszybsze lub podobnie „czyste”. Jednak po skompilowaniu z optymalizacjami na moim komputerze rozwiązanie jest znacznie szybsze.
Napisałem szybki program do zademonstrowania, a TIO ma takie same wyniki, jak znajduję lokalnie: Wypróbuj online!
Dzięki static inline
tablicy odnośników trochę przyspieszysz: wypróbuj online!
if
wciąż bije switch
(dziwne wyszukiwanie staje się jeszcze szybsze) [TIO do śledzenia]
-O3
i skompilowałem goc
do czegoś prawdopodobnie gorszego niża
lubb
(c
miał dwa skoki warunkowe plus kilka bitowych manipulacji, w porównaniu do tylko jednego skoku warunkowego i prostszego manipulowania bitamib
), ale nadal lepszy niż naiwny przedmiot według testów przedmiotów. Nie jestem pewien, o co tak naprawdę tutaj prosisz; prosty fakt jest taki, że kompilator optymalizacyjny może zmienić dowolne z nich w dowolne inne, jeśli tak zdecyduje, i nie ma twardych i szybkich reguł dotyczących tego, co zrobi lub nie zrobi.