Estoy tratando de escribir una función sin sucursales para devolver el MAX o MIN de dos enteros sin recurrir a if (o? :). Usando the usual technique me puede hacer esto con bastante facilidad para un tamaño de palabra dada:Templatized branchless int max/min función
inline int32 imax(int32 a, int32 b)
{
// signed for arithmetic shift
int32 mask = a - b;
// mask < 0 means MSB is 1.
return a + ((b - a) & (mask >> 31));
}
Ahora, suponiendo arguendo que realmente estoy escribiendo el tipo de aplicación en el tipo de procesador en el orden en que sea necesario, mi pregunta es si hay una forma de usar plantillas C++ para generalizar esto a todos los tamaños de int.
El paso >> 31 sólo funciona para int32s, por supuesto, y aunque podría copiar a cabo sobrecargas en la función para INT8, Int16, Int64 y, parece como si tuviera que utilizar una función de plantilla en su lugar. Pero, ¿cómo obtengo el tamaño de un argumento de plantilla en bits?
¿Hay una mejor manera de hacerlo que esta? ¿Puedo forzar la máscara T para que se firme? Si T no tiene firma, el paso de cambio de máscara no funcionará (porque será un cambio lógico en lugar de aritmético).
template< typename T >
inline T imax(T a, T b)
{
// how can I force this T to be signed?
T mask = a - b;
// I hope the compiler turns the math below into an immediate constant!
mask = mask >> ((sizeof(T) * 8) - 1);
return a + ((b - a) & mask);
}
Y, después de haber hecho lo anterior, puedo evitar que se utilice para otra cosa que un tipo entero (por ejemplo, no hay flotadores o clases)?
La mayoría de las máquinas modernas tienen instrucciones de mov de condiciones, que les permiten hacer mín./Máx. Sin derivaciones (p. Ej., Cmp a, b/movlt a, b). Esto sería más rápido que el código que planea generar y los compiladores lo saben. ¿Estás seguro de que tu compilador ya no lo hace por ti? –
@IraBaxter Absolutamente seguro; Siempre miro su salida de ensamblaje. Además, el procesador que objetivo (un derivado de PowerPC) definitivamente no tiene un cmov. – Crashworks
Sea cual sea el código que escriba, será sin ramas solo como fuente de C++. El compilador puede generar saltos condicionales (es decir, ramas) sin escribir if/else /? /: Y, a la inversa, puede generar instrucciones optimizadas sin sucursales de la fuente if/else. – galinette