Algorithme pour trouver une solution pour A xor X = B + X

46

Étant donné l'entier A et B, trouvez l'entier X de sorte que:

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

Je doute fortement qu'il soit possible de résoudre cette équation en utilisant les mathématiques. C'est un problème de codage que j'ai rencontré il y a 3 ans et même maintenant, je ne peux pas le résoudre moi-même.

Mon code jusqu'à présent: (c'est la solution de force brute)

#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;
}
AAaAa
la source
11
Si vous lisez un peu plus sur l' exclusivité ou vous devriez trouver l'équivalence algébrique a xor b = a + b mod 2. Essayez de réfléchir à cette équivalence pendant un petit moment.
Un programmeur du
16
@Someprogrammerdude C'est si a et b sont des variables booléennes, c'est-à-dire 0 ou 1, et xor est un xor booléen. Quelle est la connexion à xor au niveau du bit?
John Kugelman
1
fwiw, je pense que l'utilisation de la force brute ici est la voie à suivre, sauf si vous voulez écrire quelque chose qui peut prouver des équations plus générales. Considérez que vous devez tester votre code pour vous assurer qu'il est correct et le plus simple serait de le tester par rapport à un algorithme de force brute, mais vous pouvez alors utiliser la force brute en premier lieu. D'un autre côté, l'application des mathématiques rendra éventuellement inutile l'exécution de tout code.
idclev 463035818
1
@molbdnilo Oh, l'un des commentaires suggérait qu'un xor b = a + b mod 2 et je pensais qu'il faisait également référence à des entiers. Je supprimerai cette partie de mon message.
AAaAa
1
@JohnKugelman Il voulait dire le mod 2comme dans le mathématique (mod 2), ie 3 === 7 (mod 2). Le fait est que vous pouvez découvrir une équation pour le premier bit de X, puis passer au bit suivant où (en respectant le report) vous obtenez une équation pour le deuxième bit, etc., comme la réponse de Daniel.
Max Langhof

Réponses:

45

Notez cela A + X == (A xor X) + ((A and X)<<1). Donc:

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

Et nous avons:

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

Si la condition est remplie, pour tout entier Y qui n'a pas de bits définis dans A, (((A - B) >> 1) ou Y) est une solution. Si vous ne voulez qu'une seule solution, vous pouvez utiliser ((A - B) >> 1), où Y = 0. Sinon, il n'y a pas de solution.

int solve(int a, int b){
    int x = (a - b) >> 1;
    if ((a ^ x) == b + x)
        return x;
    else
        return ERROR;
}
user23013
la source
15
+1. C'est en notant que A xor Xc'est "addition sans report", et ((A and X)<<1)"report dans l'addition". Puisque A + Xc'est "addition avec report", la première équation a du sens.
1er
3
(A and X)<<1est fondamentalement 2*(A and X)et parce que cela est égal à A-Bcela dit que le problème peut avoir une solution uniquement si A et B sont tous les deux impairs ou les deux événements.
axiac
1
Je pensais que cela aurait quelque chose à voir avec la soustraction, mais je n'y suis pas arrivé à temps.
SS Anne
38

Ce n'est pas très difficile, il suffit de penser petit: supposons que nous écrivons A, Bet Xen binaire, et que Aᵢla valeur corresponde au bit 2 most le plus à droite .

Nous savons que: Aₒ ⊕ Xₒ = Bₒ + Xₒ.

Prenons un exemple pour découvrir comment évaluer cela: A = 15 et B = 6. Conversion en binaire:

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

Maintenant, nous avons quelques possibilités. Analysons les bits les plus à droite de A et B:

1  d = 0 + d

Nous savons que dcela ne peut être que 0 ou 1, donc:

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)

Il est à noter que XOR se comporte comme une somme binaire (à la différence près que XOR ne crée pas de report pour la somme de bits suivante):

    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

il ne sera donc pas toujours possible de trouver un X satisfaisant A ⊕ X = B + X, car il n'y a pas de valeur dsatisfaisante 1 + d = 0 + d.

Quoi qu'il en soit, si X existe, vous pouvez simplement le découvrir de cette façon, de droite à gauche, en le recherchant petit à petit.


EXEMPLE DE TRAVAIL COMPLET

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 

Ici, d = 0 et d = 1 s'appliquent, alors quoi? Nous devons vérifier le bit suivant. Supposons que 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)

dans ce cas, d doit être égal à 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

mais qu'en est-il de b? nous devons vérifier le bit suivant, comme toujours:

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)

et maintenant, pour 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

ici apeut être 0 et 1, mais il doit être 0, afin d'éviter un report dans la somme B + X.

Alors, X = 0 1 0 0donc X = 4.


CODE

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

Vous pouvez le tester ici .

Daniel
la source