Algoritmo per trovare una soluzione per A xor X = B + X


46

Dati i numeri interi A e B, trova il numero intero X in modo che:

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

Dubito fortemente che sia possibile risolvere questa equazione usando la matematica. Questo è un problema di codifica che ho riscontrato 3 anni fa e anche adesso non posso risolverlo da solo.

Il mio codice finora: (questa è la soluzione della forza bruta)

#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
Se leggi qualcosa in più sull'esclusiva o dovresti trovare l'equivalenza algebrica a xor b = a + b mod 2. Prova a pensare a quell'equivalenza per un po '.
Qualche programmatore, amico,

16
@Someprogrammerdude Quel se un e b sono variabili booleane, cioè 0 o 1, e xor è un XOR booleana. Qual è la connessione a bit per xor?
John Kugelman,

1
prima di tutto, penso che usare la forza bruta qui sia la strada da percorrere a meno che tu non voglia scrivere qualcosa che possa dimostrare equazioni più generali. Considera che devi testare il tuo codice per essere certo che sia corretto e che il modo più semplice sarebbe testarlo contro un algoritmo di forza bruta, ma poi puoi usare la forza bruta in primo luogo. D'altra parte, l'applicazione della matematica renderà alla fine inutile eseguire qualsiasi codice.
idclev 463035818

1
@molbdnilo Oh, uno dei commenti ha suggerito che a xor b = a + b mod 2 e ho pensato che si riferisse anche a numeri interi. Rimuoverò quella parte del mio post.
AAaAa

1
@JohnKugelman Intendeva il mod 2come nel matematico (mod 2), cioè 3 === 7 (mod 2). Il punto è che puoi scoprire un'equazione per il primo bit di X, quindi passare al bit successivo in cui (rispettando il carry) ottieni un'equazione per il secondo bit, ecc., Come la risposta di Daniel.
Max Langhof,

Risposte:


45

Si noti che A + X == (A xor X) + ((A and X)<<1). Così:

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

E noi abbiamo:

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

Se la condizione è soddisfatta, per qualsiasi numero intero Y che non ha bit impostati in A, (((A - B) >> 1) o Y) è una soluzione. Se si desidera una sola soluzione, è possibile utilizzare ((A - B) >> 1), dove Y = 0. Altrimenti non esiste soluzione.

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

15
+1. Questo è notando che A xor Xè "aggiunta senza carry", ed ((A and X)<<1)è "carry in the addition". Poiché A + Xè "aggiunta con carry", la prima equazione ha senso.
solo

3
(A and X)<<1è fondamentalmente 2*(A and X)e poiché questo è uguale A-B, dice che il problema potrebbe avere una soluzione solo se A e B sono entrambi strani o entrambi eventi.
axiac

1
Ho pensato che avrebbe avuto qualcosa a che fare con la sottrazione, ma non sono arrivato a questo in tempo.
SS Anne,

38

Non è molto difficile, devi solo pensare in piccolo: supponiamo che stiamo scrivendo A, Be Xin binario ed Aᵢè il valore corrispondente al bit 2 più a destra .

Sappiamo che: Aₒ ⊕ Xₒ = Bₒ + Xₒ.

Facciamo un esempio per scoprire come valutarlo: A = 15 e B = 6. Conversione in binario:

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

Ora abbiamo alcune possibilità. Analizziamo i bit più a destra di A e B:

1  d = 0 + d

Sappiamo che dpuò essere solo 0 o 1, quindi:

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)

È evidente che XOR si comporta proprio come la somma binaria (con la differenza che XOR non crea un riporto per la somma dei bit successiva):

    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

quindi non sarà sempre possibile trovare una X che soddisfi A ⊕ X = B + X, perché non esiste un valore dche soddisfi 1 + d = 0 + d.

Ad ogni modo, se X esiste, puoi semplicemente scoprirlo in questo modo, da destra a sinistra, trovandolo poco a poco.


ESEMPIO COMPLETO DI FUNZIONAMENTO

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 

Qui si applicano sia d = 0 che d = 1, quindi cosa? Dobbiamo controllare il prossimo bit. Supponiamo che 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)

quindi in questo caso, d deve essere 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

ma che dire di b? dobbiamo controllare il prossimo bit, come sempre:

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)

e ora, per 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

qui apuò essere 0 e 1, ma deve essere 0, al fine di evitare un riporto nella somma B + X.

Quindi, X = 0 1 0 0quindi X = 4.


CODICE

#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;
}

Puoi provarlo qui .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.