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

StackOverflow https://stackoverflow.com/questions/2791869

  •  04-10-2019
  •  | 
  •  

Вопрос

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

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

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

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

Это было полезно?

Решение

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

}

Другие советы

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

 X & 8

Это правда, если «8» бит установлен.

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

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

Если вам не волнует пространство, вы можете настроить массив Countedbits [... индексируется вашим значением с количеством предварительно возможных битов. Затем один доступ к памяти вычисляет ваш счет BIT.

Часто используется просто "Битовый Twiddling код" что вычисляет биты подсчета:

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

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

Если вы еще не видели бит Twiddling Hackdling раньше, вы находитесь для удовольствия.

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

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

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, используя & Operand.

Поскольку нет определенного ответа с 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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top