Генерировать битовые шаблоны для данной маски
моя проблема заключается в следующем: у меня есть значение x
и p
обе переменные одинакового размера. Цель состоит в том, чтобы перебрать все битовые шаблоны x, которые являются не маскируется p.
пример:
если у нас есть p = 1001
мы хотим найти 0000
, 0001
, 1000
и 1001
- Не обязательно в таком порядке.
стандартная реализация в C99 (возвращаемое значение указывает, вернули ли мы все значения уже):
static bool next(size_t val, size_t mask, size_t *out) {
if (val == mask) {
return false;
}
size_t current = val & mask;
size_t inc = 1;
size_t new_val = current + inc;
while ((new_val & mask) <= current) {
inc++;
new_val = current + inc;
}
*out = new_val;
return true;
}
Я бы подумал, что должен быть какой-то трюк, чтобы сделать это более эффективным, но я не могу найти никаких больших улучшений (кроме вычисления конечных нулей маски и установки начального значения inc соответствующим образом, что не является большим улучшением).
Edit: также важен тот факт, что для каждого сгенерированного значения генерируется много дополнительной работы, что означает, что о множестве дубликатов не может быть и речи (некоторые дубликаты, даже если не узнаваемый будет в порядке,нет никаких побочных эффектов к проделанной работе, это просто замедление).
3 ответов
Это порождает все модели в обратном порядке (начальное значение val
должно быть равно mask
):
static bool next(size_t val, size_t mask, size_t *out) {
if (val == 0) {
return false;
}
*out = (val - 1) & mask;
return true;
}
и это (немного менее очевидный код) генерирует все битовые шаблоны в прямом порядке (начальное значение val
должна быть равна нулю):
static bool next(size_t val, size_t mask, size_t *out) {
if (val == mask) {
return false;
}
*out = (val - mask) & mask;
return true;
}
из вашего примера, похоже, что этот псевдо-код сделает трюк:
current = p // set up current
getNotMasked(p, 0) // initial call
bitString current
getNotMasked(int pos)
if (pos == current.length)
print(current)
return
if (current[pos] == 1)
current[pos] = 0
getNotMasked(pos+1)
current[pos] = 1
getNotMasked(pos+1)
else
getNotMasked(pos+1)
создание кода C отсюда не должно быть сложным-заменить bitString
С int
и [pos]
С & 1 << pos
или аналогичные.
самый оптимальный способ выглядит так:
- подсчитайте количество бит в маске, p
- выяснить способ перетасовки битов из "нормализованного" двоичного значения в позицию, определяемую шаблоном
- отсчет до 0..2p-1
- для каждого значения shuffle для создания совместимого с шаблоном значения
Это, конечно, предполагает, что выполнение перетасовки достаточно эффективно, иначе это проще brute-force, просто считая от 0 до максимально возможного значения в зависимости от в общей сумме количество битов в шаблоне и применение шаблона при каждом подсчете. Обнаружение дубликатов может быть немного дорогостоящим.
на p = 9
(binary 10012), есть только два бита, поэтому мы знаем, что есть 22 = 4 значения для создания.
сканирование шаблона справа для 1-бит, мы можем сформировать следующее " перетасовка таблица":
- бит 0 копируется из бита 0
- бит 3 копируется из бита 1
Итак, мы можем считать от 0 до 3, и для каждого значения переставляем согласно таблице:
- 002 дает выход 00002
- 012 дает выход 00012
- 102 дает выход 10002
- 112 дает выход 10012