A xor X = B + X에 대한 해를 구하는 알고리즘 것이 의심 스럽다.

정수 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;
}



답변

참고하십시오 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)가 해입니다. 하나의 솔루션 만 원하면 Y = 0 인 ((A-B) >> 1)을 사용할 수 있습니다. 그렇지 않으면 솔루션이 없습니다.

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


답변

우리가 작성하는 가정 : 그것은 당신이 단지 작은 생각해야, 매우 어렵지 않습니다 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

이제 몇 가지 가능성이 있습니다. A와 B의 가장 오른쪽 비트를 분석해 봅시다 :

1  d = 0 + d

우리는 d0 또는 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

여기에서 a0과 1이 될 수 있지만 합계에서 이월을 피하려면 0이어야합니다 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;
}

여기서 테스트 할 수 있습니다 .


답변