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, bskompilowany do hacków bitowych, podczas gdy cbył albo prawie niezoptymalizowany, albo zredukowany do innego przypadku auzależ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 inlinetablicy odnośników trochę przyspieszysz: wypróbuj online!
ifwciąż bije switch(dziwne wyszukiwanie staje się jeszcze szybsze) [TIO do śledzenia]
-O3i skompilowałem gocdo czegoś prawdopodobnie gorszego niżalubb(cmiał 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.