Una solución específica eficiente de Microsoft (por ejemplo, Visual Studio 2017) en C / C ++ para la entrada de enteros. Maneja el caso de la entrada que coincide exactamente con una potencia de dos valores disminuyendo antes de verificar la ubicación del 1 bit más significativo.
inline unsigned int ExpandToPowerOf2(unsigned int Value)
{
unsigned long Index;
_BitScanReverse(&Index, Value - 1);
return (1U << (Index + 1));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#if defined(WIN64) // The _BitScanReverse64 intrinsic is only available for 64 bit builds because it depends on x64
inline unsigned long long ExpandToPowerOf2(unsigned long long Value)
{
unsigned long Index;
_BitScanReverse64(&Index, Value - 1);
return (1ULL << (Index + 1));
}
#endif
Esto genera 5 o más instrucciones en línea para un procesador Intel similar al siguiente:
dec eax
bsr rcx, rax
inc ecx
mov eax, 1
shl rax, cl
Aparentemente, el compilador de Visual Studio C ++ no está codificado para optimizar esto para valores de tiempo de compilación, pero no es que haya muchas instrucciones allí.
Editar:
Si desea que un valor de entrada de 1 produzca 1 (2 a la potencia cero), una pequeña modificación al código anterior aún genera instrucciones directas sin ramificación.
inline unsigned int ExpandToPowerOf2(unsigned int Value)
{
unsigned long Index;
_BitScanReverse(&Index, --Value);
if (Value == 0)
Index = (unsigned long) -1;
return (1U << (Index + 1));
}
Genera solo unas pocas instrucciones más. El truco es que Index puede ser reemplazado por una prueba seguida de una instrucción cmove.