Кажется, диапазон известен. Давайте предположим, что он увеличивается до 1 << 20, просто чтобы сделать его более интересным: </p>
max_log2=20
Итак, составьте список, который (по сути) отображает целое число в его логарифм с основанием 2. Следующее сделает трюк:
log2s_table=[0]*((1<<max_log2)+1)
for i in range(max_log2+1):
log2s_table[1<<i]=i
(Это не делает ничего полезного для чисел, которые не имеют степеней двойки; постановка задачи предполагает, что их не нужно обрабатывать. Хотя это было бы достаточно легко исправить.)
Функция для получения логарифма очень проста и может быть легко встроена:
def table(v):
return log2s_table[v]
Я не могу гарантировать, что код теста, который я написал, точно такой же, как тот, который используется для получения примеров времени, но это гораздо быстрее, чем код stringcount
:
stringcount: 0.43 s.
table: 0.16 s.
Поскольку все значения в таблице меньше 256, я подумал, будет ли использование строки вместо списка более быстрым, или, может быть, array.array
байтов, но без кубиков:
string: 0.25 s.
arr: 0.21 s.
Использование dict
для поиска - еще одна возможность, использующая способ проверки только степеней двух:
log2s_map=dict([(1<<x,x) for x in range(max_log2+1)])
def map(v):
return log2s_map[v]
Результаты для этого были не так хороши:
map: 0.20 s.
И просто для удовольствия можно также использовать метод hex
для объектов с плавающей точкой, чтобы получить строку, которая включает (как ее последняя часть) показатель степени 2 числа. Это немного медленно для извлечения в целом, но если показатель степени когда-либо будет только одна цифра, это может быть сделано достаточно просто:
def floathex(v):
return ord(float(v).hex()[-1])-48
Это исключительно для развлекательной ценности, хотя это было неконкурентоспособно - хотя, что удивительно, все же быстрее, чем побитовый подход.
Похоже, использование списка - это путь.
(Этот подход не будет масштабироваться бесконечно, из-за ограниченного объема памяти, но чтобы восполнить это, скорость выполнения не будет зависеть от max_log2
или входных значений, в любом случае, которые вы заметите при запуске Python-код. Что касается потребления памяти, если я правильно помню свои внутренние компоненты Python, таблица займет около (1<<max_log2)*4
байт, потому что все содержимое представляет собой небольшие целые числа, которые интерпретатор будет автоматически интернировать. Поэтому, когда max_log2
равно 20, это около 4 МБ.)