Нещодавно я працював над особистим проектом, коли натрапив на дивну проблему.
У дуже тісному циклі у мене є ціле число зі значенням від 0 до 15. Мені потрібно отримати -1 для значень 0, 1, 8, 9 і 1 для значень 4, 5, 12 і 13.
Я звернувся до godbolt, щоб перевірити кілька варіантів, і був здивований, що, здається, компілятор не зміг оптимізувати оператор перемикання так само, як ланцюг 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 дадуть однакові результати, і я сподівався, що зможу прочитати біт-хаки, щоб самостійно прийти до ефективної реалізації, оскільки моє рішення (заява переключення - в іншій формі) була досить повільною.
Як не дивно, b
компільований на біт-хаки, в той час c
як або в значній мірі неоптимізований, або зведений до іншого випадкуa
залежно від цільового обладнання.
Хтось може пояснити, чому існує ця невідповідність? Який "правильний" спосіб оптимізації цього запиту?
Редагувати:
Уточнення
Я хочу, щоб рішення комутатора було найшвидшим, або аналогічно «чистим» рішенням. Однак при компіляції з оптимізаціями на моїй машині рішення if значно швидше.
Я написав швидку програму для демонстрації, і TIO має ті самі результати, що і в мене на локальному рівні: Спробуйте в Інтернеті!
З static inline
таблицею пошуку трохи прискорюється: Спробуйте це в Інтернеті!
if
все одно б'є switch
(дивно пошук стає ще швидшим) [TIO слідкувати]
-O3
, і він компілювавсяc
до чогось, ймовірно, гіршого заa
абоb
(c
мав два умовні стрибки плюс кілька бітних маніпуляцій, порівняно лише з одним умовним стрибком і більш простим бітом manip дляb
), але все ж краще, ніж наївний предмет за предметами тестів. Я не впевнений, що ви насправді просите тут; простий факт полягає в тому, що оптимізуючий компілятор може перетворити будь-яке з них у будь-який з інших, якщо він цього захоче, і немає жорстких і швидких правил для того, що він буде чи не буде робити.