Eine effiziente Microsoft-spezifische (z. B. Visual Studio 2017) spezifische Lösung in C / C ++ für die Eingabe von Ganzzahlen. Behandelt den Fall, dass der Eingang genau mit einer Zweierpotenz übereinstimmt, indem er dekrementiert wird, bevor die Position des höchstwertigen 1-Bits überprüft wird.
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
Dies erzeugt ungefähr 5 Inline-Anweisungen für einen Intel-Prozessor, ähnlich den folgenden:
dec eax
bsr rcx, rax
inc ecx
mov eax, 1
shl rax, cl
Anscheinend ist der Visual Studio C ++ - Compiler nicht codiert, um dies für Werte zur Kompilierungszeit zu optimieren, aber es ist nicht so, dass es dort eine ganze Reihe von Anweisungen gibt.
Bearbeiten:
Wenn Sie möchten, dass ein Eingabewert von 1 1 ergibt (2 zur nullten Potenz), wird durch eine kleine Änderung des obigen Codes immer noch direkt Anweisungen ohne Verzweigung generiert.
inline unsigned int ExpandToPowerOf2(unsigned int Value)
{
unsigned long Index;
_BitScanReverse(&Index, --Value);
if (Value == 0)
Index = (unsigned long) -1;
return (1U << (Index + 1));
}
Generiert nur noch ein paar Anweisungen. Der Trick besteht darin, dass Index durch einen Test gefolgt von einer cmove-Anweisung ersetzt werden kann.