求解 A xor X = B + X 的算法

AAa*_*aAa 45 c++ xor

给定整数 A 和 B,找到整数 X 使得:

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

我非常怀疑是否有可能使用数学来解决这个方程。这是我 3 年前遇到的编码问题,即使现在我自己也无法解决。

到目前为止我的代码:(这是蛮力解决方案)

#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;
}
Run Code Online (Sandbox Code Playgroud)

use*_*013 45

请注意A + X == (A xor X) + ((A and X)<<1)。所以:

A xor X = A + X - ((A and X)<<1) = B + X
A - B = (A and X)<<1
Run Code Online (Sandbox Code Playgroud)

我们有:

(A - B) and not (A<<1) = 0    (All bits in (A - B) are also set in (A<<1))
(A - B)>>1 = A and X
Run Code Online (Sandbox Code Playgroud)

如果满足条件,对于没有在 A 中设置位的任何整数 Y, (((A - B)>>1) or Y) 是一个解决方案。如果您只需要一个解决方案,您可以使用 ((A - B)>>1),其中 Y = 0。否则就没有解决方案。

int solve(int a, int b){
    int x = (a - b) >> 1;
    if ((a ^ x) == b + x)
        return x;
    else
        return ERROR;
}
Run Code Online (Sandbox Code Playgroud)

  • +1。这是通过注意到“A xor X”是“不带进位的加法”,而“((A and X)&lt;&lt;1)”是“加法中进位”。由于“A + X”是“带进位的加法”,因此第一个方程是有意义的。 (15认同)
  • `(A and X)&lt;&lt;1` 基本上是 `2*(A and X)` 并且因为它等于 `AB` 它表示只有当 A 和 B 都是奇数或都是事件时问题才可能有解决方案。 (3认同)

Dan*_*iel 38

这不是很难,你只需要考虑小:假设我们正在编写A,B并且X是二进制的,A?并且该值对应于最右边的 2 少量。

我们知道:A? ? X? = B? + X?

让我们通过一个例子来了解如何计算:A = 15 和 B = 6。转换为二进制:

A = 1 1 1 1           B = 0 1 1 0
X = a b c d           X = a b c d
Run Code Online (Sandbox Code Playgroud)

现在我们有一些可能性。让我们分析 A 和 B 的最右边的位:

1 ? d = 0 + d
Run Code Online (Sandbox Code Playgroud)

我们知道d只能是 0 或 1,所以:

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)
Run Code Online (Sandbox Code Playgroud)

值得注意的是,XOR 的行为就像二进制和(不同之处在于 XOR 不会为下一位和创建结转):

    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
Run Code Online (Sandbox Code Playgroud)

所以不可能总能找到满足 的 X A ? X = B + X,因为不存在d满足的值1 + d = 0 + d

反正如果X存在,你就这样找吧,从右到左,一点一点的找。


工作完整示例

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 
Run Code Online (Sandbox Code Playgroud)

在这里,d = 0 和 d = 1 都适用,然后呢?我们需要检查下一位。假设 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)
Run Code Online (Sandbox Code Playgroud)

所以在这种情况下,d 必须为 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
Run Code Online (Sandbox Code Playgroud)

但是b呢?我们需要像往常一样检查下一位:

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)
Run Code Online (Sandbox Code Playgroud)

现在,对于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
Run Code Online (Sandbox Code Playgroud)

这里a可以是 0 和 1,但它必须是 0,以避免总和中的结转B + X

然后,X = 0 1 0 0,因此 X = 4。


代码

#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;
}
Run Code Online (Sandbox Code Playgroud)

你可以在这里测试它。