查找A xor X = B + X的解的算法


46

给定整数A和B,找到整数X以便:

  • A,B <2 * 1e18
  • A xor 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;
}

11
如果您阅读有关排他性的更多内容,或者应该找到代数等价物a xor b = a + b mod 2。尝试考虑一下等效性。
一些程序员花花公子

16
@Someprogrammerdude如果ab是布尔变量,即0或1,而xor是布尔xor。与按位异或的关系是什么?
John Kugelman

1
首先,我认为在这里使用蛮力是必经之路,除非您想编写可以证明更通用的方程式的东西。考虑到您必须测试您的代码以确保它是正确的,并且最简单的方法是针对蛮力算法进行测试,但是您可以首先使用蛮力。另一方面,应用数学将最终使不必运行任何代码。
idclev 463035818

1
@molbdnilo哦,评论之一建议a xor b = a + b mod 2,我认为它也指整数。我将删除帖子的这一部分。
AAaAa

1
@JohnKugelman他的意思是mod 2数学上的(mod 2),即3 === 7(mod 2)。关键是您可以发现X的第一位的等式,然后继续到下一位(尊重进位),获得第二位的等式,依此类推,就像丹尼尔的答案。
Max Langhof

Answers:


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

我们有:

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

如果满足条件,则对于任何没有在A中设置的位的整数Y,((((A-B)>>>> 1)或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;
}

15
+1。通过注意到这A xor X是“没有进位的加法”,并且((A and X)<<1)是“进位加法”。因为A + X是“加进位”,所以第一个方程是有意义的。
justhalf

3
(A and X)<<1基本上是2*(A and X)因为并且等于A-B它表示仅当A和B都为奇数或均为两个事件时,问题才可能解决。
axiac

1
我以为这与减法有关,但是我没有及时解决。
SS Anne

38

这不是很困难,您只需要考虑小一点:假设我们正在编写AB并且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

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

1  d = 0 + d

我们知道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)

值得注意的是,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

因此不可能总是找到满足的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 

在这里,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)

因此,在这种情况下,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

但是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)

现在,用于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

此处a可以为0和1,但必须为0,以避免在sum中结转B + X

然后,X = 0 1 0 0X = 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;
}

您可以在这里进行测试。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.