Генерировать битовые шаблоны для данной маски

моя проблема заключается в следующем: у меня есть значение 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 или аналогичные.


самый оптимальный способ выглядит так:

  1. подсчитайте количество бит в маске, p
  2. выяснить способ перетасовки битов из "нормализованного" двоичного значения в позицию, определяемую шаблоном
  3. отсчет до 0..2p-1
  4. для каждого значения 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