Недавно я работал над личным проектом, когда наткнулся на странную проблему.
В очень узком цикле у меня есть целое число со значением от 0 до 15. Мне нужно получить -1 для значений 0, 1, 8 и 9 и 1 для значений 4, 5, 12 и 13.
Я повернулся к Godbolt, чтобы проверить несколько вариантов, и был удивлен, что компилятор не мог оптимизировать оператор switch так же, как цепочка if.
Ссылка здесь: https://godbolt.org/z/WYVBFl
Код является:
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;
}
}
Я бы подумал, что b и c дадут одинаковые результаты, и я надеялся, что смогу прочитать побитные хаки, чтобы сам придумать эффективную реализацию, поскольку мое решение (оператор switch - в другой форме) было довольно медленным.
Как ни странно, он был b
скомпилирован в бит-хаки, но c
был либо в значительной степени неоптимизирован, либо сведен к другому случаю в a
зависимости от целевого оборудования.
Кто-нибудь может объяснить, почему существует это несоответствие? Каков «правильный» способ оптимизации этого запроса?
РЕДАКТИРОВАТЬ:
осветление
Я хочу, чтобы решение для переключения было самым быстрым или аналогичным «чистым» решением. Однако при компиляции с оптимизацией на моей машине решение if значительно быстрее.
Я написал быструю программу для демонстрации, и TIO дает те же результаты, что и на местном уровне: попробуйте онлайн!
С static inline
поисковой таблицей немного ускоряется: попробуйте онлайн!
if
все еще бьет switch
(как ни странно, поиск становится еще быстрее) [TIO, чтобы следовать]
-O3
, и он скомпилировалc
что-то, вероятно, хуже, чемa
илиb
(c
имел два условных перехода плюс несколько битовых манипуляций, по сравнению только с одним условным переходом и более простой битовой манипуляцией дляb
), но все же лучше чем наивный предмет по предметным тестам. Я не уверен, что вы действительно просите здесь; простой факт заключается в том, что оптимизирующий компилятор может превратить любой из них в любой другой, если он того пожелает, и нет жестких и быстрых правил для того, что он будет или не будет делать.