Если битовая позиция одинакова в обоих значениях, никаких изменений не требуется.Если все наоборот, они оба должны инвертировать.
XOR с 1 сальто;XOR с 0 - это неоперация.
Итак, нам нужно значение, которое имеет 1
везде, где есть разница между входами, и 0 везде.Это именно то, что делает a XOR b
.
Просто замаскируйте эту битовую разницу, чтобы сохранить только различия в битах, которые мы хотим поменять , и у нас есть бит-своп в 3 XOR +1 AND.
Ваша маска (1UL << position) -1
.Один меньше степени 2 имеет все биты ниже этого набора.Или, в более общем случае, с верхней и нижней позицией для вашего битового диапазона: (1UL << highpos) - (1UL << lowpos)
.Быстрее ли таблица поиска быстрее, чем бит-набор / подпрограмма, зависит от компилятора и аппаратного обеспечения.(См. Ответ @ PaxDiablo для предложения LUT).
// Portable C:
//static inline
void swapBits_char(unsigned char *A, unsigned char *B)
{
const unsigned highpos = 4, lowpos=0; // function args if you like
const unsigned char mask = (1UL << highpos) - (1UL << lowpos);
unsigned char tmpA = *A, tmpB = *B; // read into locals in case A==B
unsigned char bitdiff = tmpA ^ tmpB;
bitdiff &= mask; // clear all but the selected bits
*A = tmpA ^ bitdiff; // flip bits that differed
*B = tmpB ^ bitdiff;
}
//static inline
void swapBit_uint(unsigned *A, unsigned *B, unsigned mask)
{
unsigned tmpA = *A, tmpB = *B;
unsigned bitdiff = tmpA ^ tmpB;
bitdiff &= mask; // clear all but the selected bits
*A = tmpA ^ bitdiff;
*B = tmpB ^ bitdiff;
}
( Проводник компилятора Godbolt с gcc для x86-64 и ARM )
Это не обмен xor .Он использует временное хранилище.Как показывает ответ @ chux на вопрос, почти повторяющийся, подкачка xor в маске требует 3 операций AND, а также 3 XOR.(И исключает единственное преимущество XOR-swap, требуя временный регистр или другое хранилище для результатов &
.) Этот ответ является модифицированной копией моего ответа на этот другой вопрос.
Эта версия требует только1 И.Кроме того, два последних XOR не зависят друг от друга, поэтому общая задержка от входов до обоих выходов составляет всего 3 операции.(Обычно 3 цикла).
Пример этого в x86 asm см. В этом code-golf Обмен капитализации двух строк в 14 байтах машинного кода x86-64 (спрокомментированный источник asm)