Estaba trabajando en un proyecto personal recientemente cuando me topé con un problema extraño.
En un ciclo muy cerrado, tengo un número entero con un valor entre 0 y 15. Necesito obtener -1 para los valores 0, 1, 8 y 9 y 1 para los valores 4, 5, 12 y 13.
Me volví a Godbolt para verificar algunas opciones y me sorprendió que pareciera que el compilador no podía optimizar una declaración de cambio de la misma manera que una cadena if.
El enlace está aquí: https://godbolt.org/z/WYVBFl
El codigo es:
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;
}
}
Pensé que byc produciría los mismos resultados, y esperaba poder leer los trucos de bits para obtener una implementación eficiente yo mismo, ya que mi solución (la declaración de cambio, en otra forma) fue bastante lenta.
Curiosamente, se bcompiló en bit-hacks mientras no cestaba optimizado o se redujo a un caso diferente adependiendo del hardware de destino.
¿Alguien puede explicar por qué existe esta discrepancia? ¿Cuál es la forma 'correcta' de optimizar esta consulta?
EDITAR:
Aclaración
Yo quiero la solución cambie a ser el más rápido, o una solución similar "limpia". Sin embargo, cuando se compila con optimizaciones en mi máquina, la solución if es significativamente más rápida.
Escribí un programa rápido para demostrar y TIO tiene los mismos resultados que encuentro localmente: ¡ Pruébelo en línea!
Con static inlinela tabla de búsqueda se acelera un poco: ¡ Pruébelo en línea!
ifaún late switch(la búsqueda extraña se vuelve aún más rápida) [TIO a seguir]
-O3, y compilócalgo probablemente peoraob(ctenía dos saltos condicionales más algunas manipulaciones de bits, frente a un solo salto condicional y una manipulación de bits más simpleb), pero aún así mejor que las pruebas ingenuas ítem por ítem. No estoy seguro de lo que realmente estás pidiendo aquí; El simple hecho es que un compilador optimizador puede convertir cualquiera de estos en cualquiera de los otros si así lo desea, y no hay reglas estrictas para lo que hará o no hará.