Задайте диапазон бит в круговом поле бит
У меня есть бит-поле, состоящее из 64 бит:
long bitfield = 0;
Я могу установить бит для данного индекса следующим образом:
void Set(long index)
{
bitfield |= 1L << (int)(index % 64);
}
то есть. если индекс равен 0, 64, 128,... тогда устанавливается бит 0, если индекс равен 1, 65, 129,... тогда установлен бит 1 и т.д.
Вопрос: заданный индекс и счетчик (или нижний и верхний индекс), как я могу установить биты для всех индексов в этом диапазоне без использования цикла?
long SetRangeMask(int lower, int upper) // 3..7
{
if (! (lower <= upper)) throw new ArgumentException("...");
int size = upper - lower + 1; // 7 - 3 + 1 = 5
if (size >= 64) return -1;
long mask = (1 << size) - 1; // #00100000 - 1 = #000011111
return mask << lower | mask >> -lower; // #00011111 << 3 = #011111000
}
Вы можете использовать таблицу поиска для комбинированных бит-масок
Реальный простой подход, не считающийся особым случаем или оптимизациями, такими как поднятые вопросы, будет выглядеть так:
static readonly private long[] maskLUT = new long[64,64] { /* generated */ };
void SetRange(long lobit, long hibit)
{
lobit %= 64;
hibit %= 64;
bitfield |= lobit<hibit? maskLUT[lobit,hibit] : maskLUT[hibit,lobit];
}
Мысли:
вы можете рассмотреть оптимизацию, которая задана [lobit...hibit]
, если hibit-lobit
>= 64, вы можете сразу установить все биты.
В связности регионов есть немного мысли, учитывая тот факт, что обе границы могут обернуться (сначала вы обертываете обе границы, или вы обходите lobit
, и используйте дельта, чтобы найти hibit
из обернутой границы, например, с упомянутой ранее оптимизацией?)
Вы можете использовать 2 x -1, чтобы создать маску x бит длиной, затем сдвиньте ее и OR, как показано ниже:
void Set( int index, int count ) {
bitfield |= (long)(Math.Pow( 2, count ) - 1) << ((index-count) % 64);
}
Обновление: Мне нравится думать, что Math.Pow
оптимизирует полномочия от двух до левого сдвига, но это может и не быть. В этом случае вы можете получить немного больше производительности, заменив вызов на Math.Pow
на соответствующий сдвиг влево:
public void Set( int index, int count ) {
bitfield |= ((2 << count - 1) - 1) << ((index-count) % 64);
}
- Вопросы
- Bit-manipulation
- Задайте диапазон бит в круговом поле бит