在两个字节之间的给定点交换位

时间:2010-08-25 02:01:33

标签: bit-manipulation genetic-algorithm

假设我有这两个数字:

x = 0xB7
y = 0xD9

他们的二进制表示是:

x = 1011 0111
y = 1101 1001

现在我想在给定点交叉(GA),比如从第4位开始。

预期结果应为:

x = 1011 1001
y = 1101 0111

按位,我怎么能实现这个目标?

3 个答案:

答案 0 :(得分:2)

我只想使用按位运算符:

t = (x & 0x0f)
x = (x & 0xf0) | (y & 0x0f)
y = (y & 0xf0) | t

这适用于该特定情况。为了使它更具适应性,我将它放在一个函数中,例如:

def swapBits (x, y, s, e):
    lookup = [255,127,63,31,15,7,3,1]
    mask = lookup[s] & !lookup[e]
    t = x & mask
    x = (x & !mask) | (y & mask)
    y = (y & !mask) | t
    return (x,y)

查找值允许您指定要交换的位。我们将xxxxxxxxx的值yyyyyyyy与y的起始位s和6的结束位e取得一致(位数从零开始)在这个场景的左边。)

x        y        s e t        mask     !mask    execute
-------- -------- - - -------- -------- -------- -------
xxxxxxxx yyyyyyyy 2 6                   starting point
                              00111111  mask = lookup[2](00111111)
                              00111100       & !lookup[6](11111100)
                      00xxxx00          t = x & mask
xx0000xx                                x = x & !mask(11000011)
xxyyyyxx                                  | y & mask(00111100)
         yy0000yy                       y = y & !mask(11000011)
         yyxxxxyy                         | t(00xxxx00)

答案 1 :(得分:0)

Swapping individual bits with XOR

unsigned int i, j; // positions of bit sequences to swap
unsigned int n;    // number of consecutive bits in each sequence
unsigned int b;    // bits to swap reside in b
unsigned int r;    // bit-swapped result goes here

unsigned int x = ((b >> i) ^ (b >> j)) & ((1U << n) - 1); // XOR temporary
r = b ^ ((x << i) | (x << j));

答案 2 :(得分:0)

如果两个值中的位位置相同,则两者中都不需要进行任何更改。如果相反,他们都需要反转。

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 compiler explorer with gcc for x86-64 and ARM

不是xor-swap 。它确实使用临时存储。正如近似重复问题上的@chux's answer所示,屏蔽的xor-swap需要3个AND运算以及3个XOR。 (并且通过要求&结果的临时注册或其他存储来抵消XOR交换的唯一好处。)这个答案是我在另一个问题上的答案的修改副本。

此版本仅需要1 AND。此外,最后两个XOR彼此独立,因此从输入到两个输出的总延迟仅为3个操作。 (通常为3个周期)。

对于x86 asm示例,请参阅此代码-golf Exchange capitalization of two strings in 14 bytes of x86-64 machine code(带注释的asm源代码)