LINUX.ORG.RU

А как вы бы определили что установлено 2 и более флага одновременно?

 


2

3

Есть int, в котором хранится значения битовых флагов:

enum Flags
{
   F1 = 1,
   F2 = 2,
   F3 = 4,
   F4 = 8
}

Как бы вы определили, что установлены 2 или более флага одновременно? Я сделал так:

if (signum(var & F1) +
    signum(var & F2) +
    signum(var & F3) +
    signum(var & F4) > 1)
   return 1
else
   return 0;
★★

Последнее исправление: cetjs2 (всего исправлений: 2)

8 и 4 и так больше двух.

dimon555 ★★★★★
()

var& (F1|F2) == (F1|F2)

хотя если колво, тога функцию с

isSet(var, flag) {
  return (var & flag != 0) ? 1 : 0;
}

// и

count = isSet(var, F1) + isSet(var, F2)

и т.п.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)

Вполне себе решение.

Можно взять, например, gcc-изм __builtin_popcount или std::bitset::count в C++

buddhist ★★★★★
()

Нужно подойти с другой стороны 2 и более флага одновременно это не один. Из свойств бит имеем - при вычитании из степени 2 единицы получим набор единичек меньших по степени. Соответственно если установлено более двух единиц это правило будет нарушено. Отсюда результат:

(x - 1) | x == x * 2 - 1 - если установлен один флаг. Если два, и более, то не выполняется.

Как-то так короче.

ziemin ★★
()
#define B2(n)   n, n+1, n+1, n+2
#define B4(n)   B2(n),  B2(n+1), B2(n+1), B2(n+2)
   
int testflag2 (int var)
{
    static int bitcount [32] = { B4(0), B4(1) };
    return bitcount[var&15]>1;
}
anonymous
()

ох ёж. пора ++ ценик.

x&(x-1) гасит левый(младшейший) бит если бит токмо один то будет ноль если popcount>1 то не нулевой.

qulinxao ★★☆
()
Последнее исправление: qulinxao (всего исправлений: 3)
Ответ на: комментарий от anonymous_sapiens

Я ожидал этой простыни в комментах :)

sambist ★★
() автор топика
Ответ на: комментарий от ziemin

Думал о чем-то подобном, но в моем случае не проканало, ибо у меня в enum'е есть еще пара флагов, которые могут быть установлены и должны игнорироваться.

sambist ★★
() автор топика

и кстати:

>1 или >= или «что установлены 3 или более флага одновременно»

anonymous
()
Ответ на: комментарий от sambist

Да там тогда простыня получится

От пары флагов простыни не получится (F1 и F2 не учитываются):

x &= !(F1 | F2);
return (x - 1) | x != x * 2 - 1;

Как-то так.

ziemin ★★
()
Ответ на: комментарий от ziemin
/* E */ enum SmlLStyles
{
    SML_LINE_ONLYPOINTS    = (0x000001),
    SML_LINE_ALIASED       = (0x000002),
    SML_LINE_ANTIALIASED   = (0x000004),
    SML_LINE_NOFIRSTPIXEL  = (0x000008),
    SML_LINE_NOLASTPIXEL   = (0x000016)
};

проверяю наличие одновременно установленных SML_LINE_ONLYPOINTS, SML_LINE_ALIASED и SML_LINE_ANTIALIASED. Возможно еще с пяток флагов добавится, неизвестного мне пока назначения.

sambist ★★
() автор топика

return var & (var - 1) != 0;

Dendy ★★★★★
()
Ответ на: комментарий от sambist

Так а в чём суть? Проверить, стоят-ли все флаги, кроме SML_LINE_NOFIRSTPIXEL и SML_LINE_NOLASTPIXEL?

Вообще идея, что надо посчитать _количество_ флагов - какая-то странная.

legolegs ★★★★★
()

Навскидку:

return var && var > 2 && var != 4 && var != 8
Сейчас еще подумаю

alix ★★★★
()
Ответ на: комментарий от sambist

Алсо биты лучше объявлять так:

enum foobar {
AAA = (1<<0),
BBB = (1<<1),
CCC = (1<<2),
DDD = (1<<3),
};

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

Вообще идея, что надо посчитать _количество_ флагов - какая-то странная.

Но решаемая, см коменты тут: http://govnokod.ru/16375 там есть однострочник без циклов для подсчёта ненулевых бит. Но повторюсь, не это тебе надо.

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

Вообще идея, что надо посчитать _количество_ флагов - какая-то странная.

Я не хотел городить вот такое условие (которое обновлять - сдохнешь прежде чем корректно еще один флаг добавишь). Объясняю зачем - ALIASING, ANTIALIASING и ONLYPIXELS не могут стоять вместе, только кто-то один.

sambist ★★
() автор топика
Ответ на: комментарий от sambist

А какая разница?

Глаз резануло. Тут либо подчёркивать ёмкость хранения ведущими нулями либо просто писать 0x1, 0x2, ..., 0x10...

ziemin ★★
()
Ответ на: комментарий от ziemin

Я привык писать 3 байта, потому что 4 байта как-то не напишешь (ибо enum будет сводиться к signed int, а писать 0x000034FF и потом в голове инстинктивно думать, что это u32...), два байта может оказаться мало (ибо там всего 16 флагов может поместиться), а три -в самый раз.

sambist ★★
() автор топика
Ответ на: комментарий от sambist

ибо enum будет сводиться к signed int, а писать 0x000034FF

Какая разница, что к чему приводится, если ты задаёшь значения? 0x1 он что в signed, что в unsigned один хер 0x1.

ziemin ★★
()

Я бы сделал без signum:

if ((((var&F1) != 0) + ((var&F2) != 0) + ((var&F3) != 0) + ((var&F4) != 0)) > 1)
или так:

if (((var&F1 ? 1:0) + (var&F2 ? 1:0) + (var&F3 ? 1:0) + (var&F4 ? 1:0)) > 1)

Второй вариант, пожалуй, «чище».

dvl36
()
Ответ на: комментарий от Eddy_Em

Этот вариант значительно лучше: ты можешь и 32 флага выставить!

При незначительной правке можно данную шнягу и на 64 бита расширить!

Eddy_Em ☆☆☆☆☆
()

Делай как ядро linux - припиши каунтер и ин(де)кременть его. Все гениальное просто.

unt1tled ★★★★
()
Ответ на: комментарий от sambist

С точки зрения читаемости лучший вариант, имхо:

int somefunc(flags) {
  int incompatibleflags = flags & (ALIASING|ANTIALIASING|ONLYPIXELS);
  if (incompatibleflags!=ALIASING &&
      incompatibleflags!=ANTIALIASING &&
      incompatibleflags!=ONLYPIXELS)
      return 1; //error

Вот именно так. Если уж у тебя от содержимого if такой баттхёрт, можно сократить

int isPow2(int a) {
  return !(a&(a-1));
}
int somefunc(flags) {
  int incompatibleflags = flags & (ALIASING|ANTIALIASING|ONLYPIXELS);
  if (!isPow2(incompatibleflags))
    return 1; //error

Но самым правильным способом будет совместимые опции сделать флагами, а несовместимые - отдельным enum { A=0, B=1, C=2, D=3 }.

legolegs ★★★★★
()
Последнее исправление: legolegs (всего исправлений: 1)
Ответ на: комментарий от legolegs

Но самым правильным способом будет совместимые опции сделать флагами, а несовместимые - отдельным enum

Помилуйте, у меня и так в функцию идет слишком много параметров.

/* E */ SmlErrors SmlRasterDrawTetrGR(SmlIndex index, SmlTetragon tetragon, SmlTetragon corners, SmlGradient grad, SmlFStyle fstyle, SmlLStyle lstyle);
И так использовал структуры чтобы не посылать x1 y1 x2 y2 ...

sambist ★★
() автор топика
Ответ на: комментарий от sambist

Помилуйте, у меня и так в функцию идет слишком много параметров.

Ну если предметная область требует много параметров, то заметанием их под ковёр делу не поможешь.

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

Не, ну а как иначе тут сделаешь? Индекс текстуры, координаты вершин, коэффициенты скругления углов, информация о градиенте, стиль заливки и стиль линии. Из всего перечисленного не структуры - это только индекс и два последних флага.

sambist ★★
() автор топика
Ответ на: комментарий от sambist

Оформи всё это в структуру. Это полноценный state, а не просто параметры.

Deleted
()
Ответ на: комментарий от sambist

А засунуть параметры отрисовки в некую структуру «Рисуемый объект» почему не хочешь? Если их много можно даже индекс в массиве передавать (как ты, судя по всему, делаешь с текстурами).

И да - структуры хорошо бы по указателю (или ссылке в c++) передавать. Как бы так принято. А то они все в стек копируются.

ziemin ★★
()
if (var & (F1 | F2 | F3))
anonymous
()
Ответ на: комментарий от sambist

Ну и добавь параметр к функции. Да, их много, ну будет ещё один. Всяко лучше, чем держать в голове, что некоторые флаги - не флаги вовсе, а режимы.

legolegs ★★★★★
()
Ответ на: комментарий от ziemin

У него рендер же, если для каждого пикселя по указателю ходить - производительность будет не ок. Структуры «настройки рисования» тут может быть полезна, но может и не быть, я бы лишнюю сущность порождал только если она действительно нужна. Например, если критична память, то можно «настройки рисования» (флаги и режим сглаживания) упаковать чуть ли не в один байт с помощью битовых полей. Но лучше не надо.

legolegs ★★★★★
()

Если с полем допустимо работать как с числом, то находим нужное в bit twiddling hacks (а там есть и вычисление числа единичных бит, и вообще всякое), иначе два флага - это не ноль и не один:

if (var && !(var == F1 || var == F2 || var == F3 || var == F4))

в общем случае - да, суммой, но вместо signum можно использовать !!

slovazap ★★★★★
()
return ((F1|F2)&~(F3|F4)) > 0;

Первая сумма «или» - какие из флагов проверяем, вторая - какие из них игнорируем/маскируем.

blexey ★★★★★
()
Последнее исправление: blexey (всего исправлений: 2)

Про смешивание флагов которые могут быть установлены вместе и которые исключают друг друга здесь уже писали.

Кроме этого. Какова логика установки флагов? Возможно, самое простое решение - не устанавливать больше одного флага из тех, что исключают друг друга?

Я бы предложил еще такое решение: для каждого флага завести-захардкодить маску несовместимости, в которой на месте несовместимых с этим флагом битов стоят единицы, а остальные нули. Флаг устанавливать только когда логическое «и» текущего состояния и маски несовместимости этого флага равно нулю.

bogus_result
()

Второе решение: устанавливать флаг так («текущее состояние» и (не «маска несовместимости флага»)) или «флаг» ) то есть снимать все несовместимые с этим флагом биты.

Но лучше бы разобраться с логикой установки флагов: как получается, что несовместимые флаги пытаются устанавливаться вместе?

bogus_result
()

В некоторых процессорах есть инструкция pop, заботающая за 1 такт.

Deleted
()
Ответ на: комментарий от bogus_result

Какова логика установки флагов? Возможно, самое простое решение - не устанавливать больше одного флага из тех, что исключают друг друга?

Это функция для библиотеки. Вызывать ее будет пользователь. Строю «защиту от дурака».

sambist ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.