45

Given integer A and B, find integer X so that:

  • A,B < 2*1e18
  • A xor X = B + X

I highly doubt it is possible to solve this equation using maths. This is a coding problem I came across 3 years ago and even now I can't solve this myself.

My code so far: (this is the brute force solution)

#include <iostream>

using namespace std;

int main()
{

    unsigned long long a, b;
    cin >> a >> b;
    for (unsigned long long x = 1; x < max(a, b); x++) {
        unsigned long long c = a ^ x;
        unsigned long long d = b + x;
        if (c == d) {
            cout << x << endl;
            break;
            return 0;
        }
    }

    cout << -1; //if no such integer exists

    return 0;
}
6
  • 11
    If you read a little bit more about exclusive or you should find the algebraic equivalence a xor b = a + b mod 2. Try to think about that equivalence for a little while. Commented Mar 31, 2020 at 15:09
  • 16
    @Someprogrammerdude That's if a and b are Boolean variables, i.e. either 0 or 1, and xor is a Boolean xor. What's the connection to bitwise xor? Commented Mar 31, 2020 at 15:21
  • 1
    fwiw, I think using brute force here is the way to go unless you want to write something that can prove more general equations. Consider that you have to test your code to be certain that it is correct and the easiest would be to test against a brute force algorithm, but then you can use the brute force in the first place. On the other hand applying maths will eventually make it unnecessary to run any code. Commented Mar 31, 2020 at 15:41
  • 1
    @molbdnilo Oh, one of the comments suggested that a xor b = a + b mod 2 and I thought it also referred to integers. I will remove that part of my post.
    – AAaAa
    Commented Mar 31, 2020 at 15:51
  • 1
    @JohnKugelman He meant the mod 2 as in the mathematical (mod 2), i.e. 3 === 7 (mod 2). The point is that you can discover an equation for the first bit of X, then go on to the next bit where (respecting the carry) you get an equation for the second bit, etc., like Daniel's answer. Commented Apr 1, 2020 at 17:29

2 Answers 2

46

Note that A + X == (A xor X) + ((A and X)<<1). So:

A xor X = A + X - ((A and X)<<1) = B + X
A - B = (A and X)<<1

And we have:

(A - B) and not (A<<1) = 0    (All bits in (A - B) are also set in (A<<1))
(A - B)>>1 = A and X

If the condition is met, for any integer Y that doesn't have bits that are set in A, (((A - B)>>1) or Y) is a solution. If you want just one solution, you could use ((A - B)>>1), where Y = 0. Otherwise there is no solution.

int solve(int a, int b){
    int x = (a - b) >> 1;
    if ((a ^ x) == b + x)
        return x;
    else
        return ERROR;
}
3
  • 15
    +1. This is by noting that A xor X is "addition without carry", and ((A and X)<<1) is "carry in the addition". Since A + X is "addition with carry", the first equation makes sense.
    – justhalf
    Commented Apr 1, 2020 at 6:39
  • 3
    (A and X)<<1 is basically 2*(A and X) and because this is equal to A-B it says that the problem may have a solution only if A and B are both odd or both event.
    – axiac
    Commented Apr 1, 2020 at 9:53
  • 1
    I thought it would have something to do with subtraction but I didn't come to this in time.
    – S.S. Anne
    Commented Apr 1, 2020 at 14:25
39

It's not very hard, you just need to think small: suppose we are writing A, B and X in binary and Aᵢ is the value corresponding to the rightmost 2 bit.

We know that: Aₒ ⊕ Xₒ = Bₒ + Xₒ.

Let's use an example to discover how to evaluate that: A = 15 and B = 6. Converting to binary:

A = 1 1 1 1           B = 0 1 1 0
X = a b c d           X = a b c d

Now we have some possibilities. Let's analyse the rightmost bits of A and B:

1 ⊕ d = 0 + d

We know that d can only be 0 or 1, so:

for d = 0
1 ⊕ d = 0 + d    =>    1 ⊕ 0 = 0 + 0    =>    1 = 0 (not possible)

for d = 1
1 ⊕ d = 0 + d    =>    1 ⊕ 1 = 0 + 1    =>    0 = 1 (not possible)

It's noticeable that XOR behaves just like binary sum (with the difference that XOR doesn't create a carryover for the next bit sum):

    XOR           SUM
0 ⊕ 0 = 0  |   0 + 0 = 0
0 ⊕ 1 = 1  |   0 + 1 = 1
1 ⊕ 0 = 1  |   1 + 0 = 1
1 ⊕ 1 = 0  |   1 + 1 = 0

so it won't be always possible to find a X that satisfies A ⊕ X = B + X, because there isn't a value d that satisfies 1 + d = 0 + d.

Anyway, if X exists, you can just find it out this way, from right to left, finding bit by bit.


WORKING FULL EXAMPLE

A = 15, B = 7:

A = 1 1 1 1           B = 0 1 1 1
X = a b c d           X = a b c d

1 ⊕ d = 1 + d 

Here, both d = 0 and d = 1 apply, then what? We need to check the next bit. Suppose d = 1:

A = 1 1 1 1           B = 0 1 1 1
X = a b c d           X = a b c d

1 ⊕ d = 1 + d    =>    1 ⊕ 1 = 1 + 1    =>    0 = 0 (possible)

BUT 1 + 1 = 0 generates a carryover for the next bit sum:

Instead of 1 ⊕ c = 1 + c, we have 1 ⊕ c = 1 + c (+1) =
                                   1 ⊕ c = c  (not possible)

so in this case, d must be 0.

carryover                              0
         A = 1 1 1 1           B = 0 1 1 1
         X = a b 0 0           X = a b 0 0
        -----------------------------------
                   0                     0

we know that c must be 0:

carryover                            0 0
         A = 1 1 1 1           B = 0 1 1 1
         X = a b 0 0           X = a b 0 0
        -----------------------------------
                 1 1                   1 1

but what about b? we need to check the next bit, as always:

if b = 0, there won't be a carryover, so we'll have:

1 ⊕ a = 0 + a  (and this is not possible)

so we try b = 1:

1 ⊕ b = 1 + b    =>    1 ⊕ 1 = 1 + 1    =>    0 = 0 (with carryover)

and now, for a:

carryover                          1 0 0
         A = 1 1 1 1           B = 0 1 1 1
         X = a 1 0 0           X = a 1 0 0
        -----------------------------------
               0 0 0                 0 0 0


1 ⊕ a = 0 + a (+1)    =>    1 ⊕ a = 1 + a

here a can be 0 and 1, but it must be 0, in order to avoid a carryover in the sum B + X.

Then, X = 0 1 0 0, thus X = 4.


CODE

#include <iostream>
using namespace std;

inline int bit(int a, int n) {
    if(n > 31) return 0; 
    return (a & ( 1 << n )) >> n; 
}

int main(){
    int A = 19;
    int B = 7;

    int X = 0;
    int carryover = 0;
    int aCurrent, aNext, bCurrent, bNext;

    for(int i = 0; i < 32; i++){
        aCurrent =  bit(A, i);      bCurrent =  bit(B, i);
        aNext =     bit(A, i + 1);  bNext =     bit(B, i + 1);

        if(aCurrent == 0 && bCurrent == 0){
            if(carryover) {X = -1; break;}
            if(aNext != bNext){
                X += 1 << i;
            }
            carryover = 0;
        }
        else if(aCurrent == 0 && bCurrent == 1){
            if(!carryover) {X = -1; break;}
            if(aNext == bNext){
                X += 1 << i;
            }
            carryover = 1;
        }
        else if(aCurrent == 1 && bCurrent == 0){
            if(!carryover) {X = -1; break;}
            if(aNext != bNext){
                X += 1 << i;
                carryover = 1;
            }
            else {
                carryover = 0;
            }
        }
        else if(aCurrent == 1 && bCurrent == 1){
            if(carryover) {X = -1; break;}
            if(aNext != bNext){
                X += 1 << i;
                carryover = 1;
            }
            else {
                carryover = 0;
            }
        }

    }

    if(X != -1) cout<<"X = "<<X<<endl;
    else cout<<"X doesnt exist"<<endl;

    return 0;
}

You can test it here.

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.