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 인 경우입니다. 비트 xor와의 연결은 무엇입니까?
John Kugelman

1
fwiw, 나는 좀 더 일반적인 방정식을 증명할 수있는 무언가를 쓰고 싶지 않다면 무차별 힘을 사용하는 것이 좋습니다. 코드가 올바른지 확인하기 위해 코드를 테스트해야하고 가장 쉬운 방법은 무차별 대입 알고리즘을 테스트하는 것이지만 처음에는 무차별 대입을 사용할 수 있습니다. 반면에 수학을 적용하면 결국에는 코드를 실행할 필요가 없습니다.
idclev 463035818

1
@molbdnilo 아, 의견 중 하나는 a xor b = a + b mod 2라고 제안했으며 정수라고도 생각했습니다. 내 게시물의 해당 부분을 제거하겠습니다.
AAaAa

1
@JohnKugelman 그는 mod 2수학 (mod 2)에서와 같이, 즉 3 === 7 (mod 2)을 의미했습니다. 요점은 X의 첫 번째 비트에 대한 방정식을 찾은 다음 Daniel의 답변과 같이 두 번째 비트에 대한 방정식을 얻는 캐리 (carry)를 나타내는 다음 비트로 넘어갑니다.
Max Langhof

답변:


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)가 해입니다. 하나의 솔루션 만 원하면 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;
}

15
+1. 이것은 A xor X"운반하지 않고 추가"이고 "추가로 수행"이라는 점에 주목합니다 ((A and X)<<1). A + X"carry를 사용한 추가" 이므로 첫 번째 방정식이 의미가 있습니다.
justhalf

3
(A and X)<<1는 기본적 2*(A and X)으로이 값과 같기 때문에 A-BA와 B가 모두 홀수이거나 이벤트 일 경우에만 문제가 해결 될 수 있습니다.
axiac

1
나는 그것이 뺄셈과 관련이 있다고 생각했지만 제 시간에 오지 않았습니다.
SS Anne

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

이제 몇 가지 가능성이 있습니다. 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;
}

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.