Создание и использование битовой маски в PHP

PHP

Пример создание и использование битовой маски в PHP

Пишу этот материал только потому, что сам долго вникал, что к чему)))
Наверное, чтоб проще понять как использовать битовую маску (bitmask), нужно на примере показать, для чего она используется.

Пример использования битовой маски:
Задача
На сайте есть система опроса пользователей, которая содержит 10 вариантов ответа. Каждый вариант имеет свой уникальный номер — ID. Ответы нужно сохранять в БД.

Решение
Можно конечно, не заморачиваться и сделать для каждого варианта ответа отдельное поле в таблице результатов, но это не наши методы. Мы попробуем хранить все ответы в одном поле типа INT.

Предположим, что модуль голосования прислал нам массив результатов:
array(1,2,3,12);
это значит, что пользователь указал в голосовании пункты 1,2,3,12. Давайте представим результат нашего голосования как строку из 0 и 1, в которой 1 соответствуют выбранные в голосовании пункты. В результате такого преобразования мы получим число 100000000111 в двоичной системе, что будет соответствовать числу 2055 в десятичной системе.

Для создания битовой маски используем следующую функцию:
function arrayValue2BitMask(array $inputArray)
{
    $bitMask = 0;
    foreach ($inputArray as $val) {
        $bitMask = $bitMask | 1 << ($val - 1);
    }
    return $bitMask;
}
Результат работы функции arrayValue2BitMask() как раз и будет число INT = 2055. Которое мы можем смело сохранять в БД.
проверка значения бита
Но как нам проверить значение бита с определённым номером (помним, что номера бит начинаются с 0, справа). Для проверки создадим ещё одну функцию:
function getBit($bitMask, $bitNum)
{
    return $bitMask & 1 << $bitNum;
}
В качестве параметров функция getBit() принимает:
  • $bitMask — битовую маску (в нашем случае 100000000111)
  • $bitNum — номер бита, помним, что номера бит начинаются с 0, справа.
Результатом выполнения функции будет число 1, если бит = 1, или 0, если бит = 0. MySQL так же в свое выборке поддерживает выражения
WHERE poll_result & 1 << 7
Запрос с таким условием выберет все записи, у которых в поле poll_result 8-й бит равен 1, тут главное зафиксировать для себе то факт, что номер бита начинается с 0.

Для тех, кто прочитал и ничего не понял (как я в первый раз))))
Хочу более подробно расписать создание битовой маски, для наглядности буду использовать код PHP:
// переменная, которая будет результатом создания маски
$bitMask  = 0; // в двоичной системе это 0, или 0000 для облегчения восприятия задачи
// нужно создать маску 1101
// для это изменим 0,2,3 биты на 1. Как это сделать, нужно выполнить битовой сравнение OR (или) с битом 
// в существующей маске,у нас 0000 ($bitMask).
// $bitMask = $bitMask | 1 << 0 
// значит, что мы берём 1 и смещаем на 0 позицию, и дальше сравниваем с битом который есть $bitMask = 0000;
// в логической записи это выглядело бы так 0 ИЛИ 1 = 1;
$bitMask = $bitMask | 1 << 0;
// $bitMask = $bitMask | 1 << 2 
// значит, что мы берём 1 и смещаем на 2 позицию, и дальше сравниваем с битом который есть $bitMask = 0001;
// в логической записи это выглядело бы так 0 ИЛИ 1 = 1;
$bitMask = $bitMask | 1 << 2; 
// $bitMask = $bitMask | 1 << 3;
// значит, что мы берём 1 и смещаем на 3 позицию, и дальше сравниваем с битом который есть $bitMask = 0101;
// в логической записи это выглядело бы так 0 ИЛИ 1 = 1;
$bitMask = $bitMask | 1 << 3; 
// результатом всех этих операций будет десятичное число 13 или двоичное 1101, которое используем как маску
echo $bitMask; // результат 13
// чтоб увидеть число в двоичной системе можно выполнить функцию преобразования
echo decbin($bitMask); // результат 1101

Вот теперь, наверное, всё) Надеюсь, будет полезно как и мне)
  • +1
  • 26 сентября 2014, 16:45
  • igorrius

Комментарии (0)

RSS свернуть / развернуть
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.
comments powered by Disqus