То, что вы скопировали, является шаблоном для генерации кода. Не стоит транслитерировать этот шаблон на другой язык и ожидать, что он будет работать быстро. Давайте расширим шаблон.
(T) ~ (T) 0 означает «столько 1-бит, сколько подходит для типа T». Алгоритму нужны 4 маски, которые мы рассчитаем для различных T-размеров, которые могут нас заинтересовать.
>>> for N in (8, 16, 32, 64, 128):
... all_ones = (1 << N) - 1
... constants = ' '.join([hex(x) for x in [
... all_ones // 3,
... all_ones // 15 * 3,
... all_ones // 255 * 15,
... all_ones // 255,
... ]])
... print N, constants
...
8 0x55 0x33 0xf 0x1
16 0x5555 0x3333 0xf0f 0x101
32 0x55555555L 0x33333333L 0xf0f0f0fL 0x1010101L
64 0x5555555555555555L 0x3333333333333333L 0xf0f0f0f0f0f0f0fL 0x101010101010101L
128 0x55555555555555555555555555555555L 0x33333333333333333333333333333333L 0xf0f0f0f0f0f0f0f0f0f0f0f0f0f0f0fL 0x1010101010101010101010101010101L
>>>
Вы заметите, что маски, сгенерированные для 32-битного регистра, совпадают с масками в жестко запрограммированном 32-битном C-коде. Детали реализации: потеря суффикса L
из 32-битных масок (Python 2.x) и потеря всех суффиксов L
для Python 3.x.
Как видите, весь шаблон и каперсы (T) ~ (T) 0 - просто запутанная софистика. Проще говоря, для k-байтового типа вам нужно 4 маски:
k bytes each 0x55
k bytes each 0x33
k bytes each 0x0f
k bytes each 0x01
и окончательный сдвиг составляет всего N-8 (то есть 8 * (k-1)) битов. Кроме того: я сомневаюсь, что код шаблона действительно будет работать на машине, у которой CHAR_BIT не было 8, но в наши дни их не так много.
Обновление: есть еще один момент, который влияет на правильность и скорость при транслитерации таких алгоритмов с C на Python. Алгоритмы C часто предполагают целые числа без знака. В C операции над целыми числами без знака работают без вывода сообщений по модулю 2 ** N. Другими словами, сохраняются только младшие N битов. Нет исключений переполнения. Многие битовые алгоритмы полагаются на это. Однако (а) Python int
и long
подписаны (б) старый Python 2.X вызовет исключение, последние Python 2.X будут молча продвигать int
до long
и Python 3.x int
== Python 2.x long
.
Проблема корректности обычно требует register &= all_ones
хотя бы один раз в коде Python. Тщательный анализ часто требуется для определения минимальной правильной маскировки.
Работа в long
вместо int
не сильно влияет на эффективность. Вы заметите, что алгоритм для 32 бит вернет ответ long
даже со входа 0
, потому что 32-битные all_ones long
.