Wydajne rozwiązanie specyficzne dla Microsoft (np. Visual Studio 2017) w C / C ++ dla wprowadzania liczb całkowitych. Obsługuje przypadek wejścia dokładnie dopasowującego potęgę dwóch wartości poprzez zmniejszenie przed sprawdzeniem lokalizacji najbardziej znaczącego 1 bitu.
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
To generuje 5 lub mniej instrukcji dla procesora Intel podobnego do następującego:
dec eax
bsr rcx, rax
inc ecx
mov eax, 1
shl rax, cl
Najwyraźniej kompilator Visual Studio C ++ nie jest zakodowany w celu zoptymalizowania tego pod kątem wartości czasu kompilacji, ale nie jest tak, że zawiera wiele instrukcji.
Edytować:
Jeśli chcesz, aby wartość wejściowa 1 dawała 1 (2 do mocy zerowej), niewielka modyfikacja powyższego kodu nadal generuje bezpośrednie instrukcje bez rozgałęzienia.
inline unsigned int ExpandToPowerOf2(unsigned int Value)
{
unsigned long Index;
_BitScanReverse(&Index, --Value);
if (Value == 0)
Index = (unsigned long) -1;
return (1U << (Index + 1));
}
Generuje tylko kilka instrukcji. Sztuka polega na tym, że indeks można zastąpić testem, a następnie instrukcją cmove.