SilenceOfWinter
@SilenceOfWinter
та еще зажигалка...

Как проверить корретность битовой маски?

Пример:
Eсть "флаги": a = 1, b = 2, c = 6
Значение должно является битовой маской содержащей от 1 до 3 флагов:
a, b, c
a | b, a | c, b | c
a | b | c

Как проверить значение? например, 7 - верно (a | c), а 4 или 11 - не верно.
  • Вопрос задан
  • 495 просмотров
Решения вопроса 1
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
У вас не битовая маска, так как b и c содержат один и тот же бит 2 и отличить c от b|c невозможно. 2|6 === 6. В битовой маске все уникальные некомбинированные флаги должны быть степенями двойки.
Работать с вашим набором можно, но флаги придётся складывать через +, а проверять своей функцией, наподобие такой:
function flags($value) {
    if (!in_array($value, [0, 1, 2, 3, 6, 7, 8, 9])) {
        return false;
    }
    $result = [];
    if (in_array($value, [1, 3, 7, 9])) {
        $result[] = 'a';
    }
    if (in_array($value, [2, 3, 8, 9])) {
        $result[] = 'b';
    }
    if (in_array($value, [6, 7, 8, 9])) {
        $result[] = 'c';
    }
    return $result;
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
dollar
@dollar
Делай добро и бросай его в воду.
Корректность битовой маски обычно не проверяется, потому что обычно нет нормальных критериев. По сути каждый флаг - это степень двойки (или отдельный "бит"). Таким образом, правильная маска - это просто число от 0 до максимально возможного, когда все флаги включены. В этом диапазоне обычно нет дырок. Для понятности попробуйте записывать маску в двоичном формате.

Предположим, у вас есть пять "флагов": a=1, b=2, c=4, d=8, e=16,
тогда значение маски будет от 0 до 31 (т.е. макс. 11111). По выходу за диапазон можно сказать, что она некорректна. Но если у вас 32 флага в маске типа uint, то выход за диапазон не возможен в принципе, и любая маска будет корректной.

Предположим, у вас теперь 4 флага: a=1, b=2, d=8, e=16,
то есть не хватает c=4. Тогда это как бы дырка в маске.
Проверяем этот бит: (mask & 4 == 4)
По идее, если этот бит установлен, то маска некорректна. Но с другой стороны, целевой алгоритм может просто игнорировать бит, который не используется. Так что лишние биты не делают маску некорректной.

Ну и, наконец, возможен уже реальный критерий, когда логика флагов такова, что не все комбинации возможны. Хотя такие кейсы лучше вообще не флагами решать, тем не менее бывает. Например, запрещено устанавливать одновременно b=2 и e=16, тогда условие некорректности будет следующее:
(mask & 2 > 0) && (mask & 16 > 0)
Либо короче:
(mask & (b | e) > 0)
(mask & 18 > 0)

Аналогично проверяется любое другое условие, накладываемое на маску. Например, если количество включённых флагов лимитировано, то просто считаем количество бит в маске.

P.S. И да, c=6 это некорректный флаг, потому что содержит b=2, и вы никак не определите, является ли mask=c или же mask=b|c.
Ответ написан
BacCM
@BacCM
C++ почти с рождения
Можно наложить по AND все инверсированные значения флагов и если будет не 0 то есть лишний "неверный" бит
На C

size_t value = // Откуда-то получили

bool isValid = (value & ~(MASK1 | MASK2 | MASK3)) == 0;
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы