Самый эффективный способ извлечения битовых флагов

У меня есть эти возможные битовые флаги.

1, 2, 4, 8, 16, 64, 128, 256, 512, 2048, 4096, 16384, 32768, 65536 

Таким образом, каждое число похоже на истинное / ложное утверждение на стороне сервера. Поэтому, если первые 3 элемента, и только первые 3 элемента отмечены как «истинные» на стороне сервера, веб-служба вернет 7. Или, если все 14 элементов выше являются истинными, я все равно получаю один номер из веб-сервис, который является суммой всех этих чисел.

Каков наилучший способ обработки числа, которое я возвращаю, чтобы узнать, какие элементы отмечены как «истинные»?

 if (7 & 1) { // if bit 1 is set in returned number (7) } 

Используйте оператор маскировки. На языке C:

  X & 8 

true, если бит «8» установлен.

Вы можете перечислить бит-маски и подсчитать, сколько из них установлено.

Если это действительно так, что все слово содержит биты, и вы хотите просто вычислить, сколько бит установлено, вы хотите по существу «подсчет населения». Абсолютным самым быстрым способом получения подсчета населения является выполнение собственного «popcnt», обычно доступного в наборе команд вашего компьютера.

Если вам небезразлично пространство, вы можете настроить подсчет массива […], индексированный по вашему значению, с помощью предварительно вычисленного количества бит. Затем один доступ к памяти вычисляет количество бит.

Часто используется просто «бит-скручивающий код», который вычисляет количество бит:

(Метод Кернигана):

 unsigned int v; // count the number of bits set in v unsigned int c; // c accumulates the total bits set in v for (c = 0; v; c++) { v &= v - 1; // clear the least significant bit set } 

(суммирование параллельного бита, 32 бита)

 v = v - ((v >> 1) & 0x55555555); // reuse input as temporary v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp c = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count 

Если вы раньше не видели бит-халаты, вы должны угоститься.

PHP, будучи смешным, может делать смешные вещи с некоторыми из этих арифметических действий.

Мысль о том, что вопрос старый, может помочь кому-то другому. Я помещаю числа в двоичном формате, чтобы понять их. Код не был протестирован, но надеюсь, что логика понятна. Код специфичен для PHP.

 define('FLAG_A', 0b10000000000000); define('FLAG_B', 0b01000000000000); define('FLAG_C', 0b00100000000000); define('FLAG_D', 0b00010000000000); define('FLAG_E', 0b00001000000000); define('FLAG_F', 0b00000100000000); define('FLAG_G', 0b00000010000000); define('FLAG_H', 0b00000001000000); define('FLAG_I', 0b00000000100000); define('FLAG_J', 0b00000000010000); define('FLAG_K', 0b00000000001000); define('FLAG_L', 0b00000000000100); define('FLAG_M', 0b00000000000010); define('FLAG_N', 0b00000000000001); function isFlagSet($Flag,$Setting,$All=false){ $setFlags = $Flag & $Setting; if($setFlags and !$All) // at least one of the flags passed is set return true; else if($All and ($setFlags == $Flag)) // to check that all flags are set return true; else return false; } 

Применение:

 if(isFlagSet(FLAG_A,someSettingsVariable)) // eg: someSettingsVariable = 0b01100000000010 if(isFlagSet(FLAG_A | FLAG_F | FLAG_L,someSettingsVariable)) // to check if atleast one flag is set if(isFlagSet(FLAG_A | FLAG_J | FLAG_M | FLAG_D,someSettingsVariable, TRUE)) // to check if all flags are set 

Одним из способов было бы перебрать ваш номер, сдвинув его слева (т. Е. Разделив на 2) и сравнить первый бит с 1 с помощью операнда &.

Поскольку нет определенного ответа на php-код, я добавляю этот рабочий пример:

 // returns array of numbers, so for 7 returns array(1,2,4), etc.. function get_bits($decimal) { $scan = 1; $result = array(); while ($decimal >= $scan){ if ($decimal & $scan) $result[] = $scan; $scan<<=1; } return $result; }