Ответ 1
В цикле for
выполняется столько элементов, которые заполняются в массив buf
. Для каждого из этих элементов он вычисляет количество бит, которые заданы в этом элементе (бит-скрипт с t
делает именно это), и который добавляется в cnt
. В конце возвращается cnt
(или 1, если cnt
равно 0).
Объяснение для бит-бит:
Строка бит-бит 1
Строка t = t - ((t >> 1) & 0x5555555555555555ULL);
в основном группирует биты t
на 2 бита и заменяет каждую группу числом числа установленных битов в этой группе. Это работает следующим образом:
Рассмотрим t = ... w x y z
, где w, x, y, z - отдельные биты. Тогда
t = ... w x y z
t>>1 = ..... w x y
t>>1 & 0x...55ULL = ... 0 w 0 y
Сверху ясно, почему группировка происходит в 2 бита (например, y и z объединяются вместе). Теперь t - ((t >> 1) & 0x5555555555555555ULL)
будет иметь каждую группу из 2 бит y z
, преобразованную в (y-z)
. Используя таблицу из 4-х возможностей (00, 01, 10, 11), мы видим, что ответы (00, 01, 01, 10) соответствуют числу битов, установленных в этой группе из 2 бит.
Строка бит-бит 2
Переходя к следующей строке бит-бит t = (t & 0x3333333333333333ULL) + ((t >> 2) & 0x3333333333333333ULL);
, мы видим, что она добавляет соседние группы из 2 в группы по 2.
t & 0x..33ULL
принимает самые правые 2 бита каждой группы из 4 бит. (t>>2) & 0x..33ULL
принимает самые левые 2 бита каждой группы из 4 бит и сдвигает их вправо на 2.
Поскольку эти две группы из 2 битов были числом бит, установленным в исходном номере, оно добавило количество бит, установленных в каждой группе из 4 бит. (то есть теперь каждая группа из 4 бит имеет количество бит, которые первоначально были установлены в этих позициях)
Строка бит-бит 3
Что касается последней строки бит-бит cnt += (int32)((((t + (t >> 4)) & 0xF0F0F0F0F0F0F0FULL) * 0x101010101010101ULL) >> 56);
, мы можем разбить ее на несколько частей для более легкого понимания.
(int32)(
(
(
(
t + (t >> 4)
) & 0xF0F0F0F0F0F0F0FULL
) * 0x101010101010101ULL
) >> 56
)
В настоящее время каждая группа из 4 бит хранит количество бит, которые первоначально были установлены в номере. Сдвигая число на 4 и добавляя вместе все связанные группы. &
ing с 0x..0F0FULL
выбирает правильные 4 бита каждой группы из 8 бит. Следовательно, в конце (t + (t >> 4)) & 0x...0F0FULL
существуют группы из 8 бит, которые содержат количество бит, которые были там в этих местах исходного номера. Позвольте просто называть это число s = (t + (t >> 4)) & 0x...0F0FULL
для простоты.
Теперь нам нужно сделать (s * 0x...0101ULL) >> 56
. Обратите внимание, что t
и, следовательно, s
имеют размер 64 бит. Это означает, что существует 8 групп из 8 бит. Простым умножением на 0x...0101ULL
(который является только самым правым битом, включенным для каждой группы), самая левая группа теперь будет суммой всех групп. Перемещаясь правым на 56 (т.е. (64 - 8)
), мы переместим эту левую группу в самое ровное положение. Это означает, что самая правая группа из 8 бит теперь имеет сумму всех групп s
. Но группы s
были числом заданных битов в этих местах в номере, поэтому после операции >>56
мы имеем общее количество заданных бит в исходном номере. (int32)
просто приписывается типу данных меньшего размера (этого достаточно, чтобы сохранить это число.
Примечание. Установленный бит означает, что бит равен 1.