Указанная выше __popcount
не работает в ARM или даже во всех процессорах x86 (для этого требуется набор инструкций ABM ). Вы не должны использовать это непосредственно; вместо этого, если вы используете x86 / amd64, вы должны использовать встроенную функцию __cpuid
, чтобы определить во время выполнения, поддерживает ли процессор popcnt
.
Имейте в виду, что вы, вероятно, не хотите выдавать cpuid
за каждый popcnt
звонок; Вы хотите сохранить результат где-нибудь. Если ваш код всегда будет однопоточным, это тривиально, но если вы хотите быть поточно-ориентированным, вам придется использовать что-то вроде One-Time Initialization . Это будет работать только с Windows ≥ Vista; если вам нужно работать со старыми версиями, вам нужно будет свернуть свою собственную (или использовать что-то от стороннего производителя).
Для машин без ABM (или если обнаружение во время выполнения не стоит), есть несколько портативных версий на Bit Twiddling Hacks (см. «Набор подсчитанных битов»). Моя любимая версия работает для любого типа T
до 128 бит:
v = v - ((v >> 1) & (T)~(T)0/3); // temp
v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3); // temp
v = (v + (v >> 4)) & (T)~(T)0/255*15; // temp
c = (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * CHAR_BIT; // count
Если вам нужна встроенная версия, вы можете использовать встроенный модуль в portable-snippets (полное раскрытие: portable-snippets - один из моих проектов), который должен работать практически везде.