Лучшим вариантом на моей голове был бы подход O (log (logn)), использующий бинарный поиск. Вот пример для 64-битного (<= 2^63 - 1
) числа (в C ++):
int log2(int64_t num) {
int res = 0, pw = 0;
for(int i = 32; i > 0; i --) {
res += i;
if(((1LL << res) - 1) & num)
res -= i;
}
return res;
}
Этот алгоритм в основном предоставит мне наибольшее число разрешений, например (2^res - 1 & num) == 0
. Конечно, для любого числа вы можете решить это в аналогичном вопросе:
int log2_better(int64_t num) {
var res = 0;
for(i = 32; i > 0; i >>= 1) {
if( (1LL << (res + i)) <= num )
res += i;
}
return res;
}
Обратите внимание, что этот метод основан на том факте, что операция "сдвиг битов" более или менее равна O (1). Если это не так, вам придется предварительно вычислить либо все степени 2, либо числа вида 2^2^i
(2 ^ 1, 2 ^ 2, 2 ^ 4, 2 ^ 8 и т. Д.) И выполнить некоторые умножения (которые в этом случае больше не O (1)).