2

Let's say I have these two numbers:

x = 0xB7 y = 0xD9 

Their binary representations are:

x = 1011 0111 y = 1101 1001 

Now I want to crossover (GA) at a given point, say from position 4 onwards.

The expected result should be:

x = 1011 1001 y = 1101 0111 

Bitwise, how can I achieve this?

3 Answers 3

2

I would just use bitwise operators:

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

That would work for that specific case. In order to make it more adaptable, I'd put it in a function, something like (pseudo-code, with &, | and ! representing bitwise "and", "or", and "not" respectively):

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) 

The lookup values allow you to specify which bits to swap. Let's take the values xxxxxxxx for x and yyyyyyyy for y along with start bit s of 2 and end bit e of 6 (bit numbers start at zero on the left in this scenario):

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) 
Sign up to request clarification or add additional context in comments.

1 Comment

It's not obvious that a LUT is better than (1<<s) - (1<<e). And BTW, you can swap bits with only 3 XORs + 1 AND: see my answer.
1

If a bit position is the same in both values, no change is needed in either. If it's opposite, they both need to invert.

XOR with 1 flips a bit; XOR with 0 is a no-op.

So what we want is a value that has a 1 everywhere there's a bit-difference between the inputs, and a 0 everywhere else. That's exactly what a XOR b does.

Simply mask this bit-difference to only keep the differences in the bits we want to swap, and we have a bit-swap in 3 XORs + 1 AND.

Your mask is (1UL << position) -1. One less than a power of 2 has all the bits below that set. Or more generally with a high and low position for your bit-range: (1UL << highpos) - (1UL << lowpos). Whether a lookup-table is faster than bit-set / sub depends on the compiler and hardware. (See @PaxDiablo's answer for the LUT suggestion).

// 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)

This is not an xor-swap. It does use temporary storage. As @chux's answer on a near-duplicate question demonstrates, a masked xor-swap requires 3 AND operations as well as 3 XOR. (And defeats the only benefit of XOR-swap by requiring a temporary register or other storage for the & results.) This answer is a modified copy of my answer on that other question.

This version only requires 1 AND. Also, the last two XORs are independent of each other, so total latency from inputs to both outputs is only 3 operations. (Typically 3 cycles).


For an x86 asm example of this, see this code-golf Exchange capitalization of two strings in 14 bytes of x86-64 machine code (with commented asm source)

1 Comment

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)); 

1 Comment

That swaps two (non-overlapping) bitfields within one unsigned int. There's only one input (b) and one output (r). It's not a helpful starting point for a masked xor-swap of corresponding bits between two values.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.