Algoritma untuk menemukan solusi untuk A xor X = B + X

46

Bilangan bulat A dan B yang diberikan, temukan bilangan bulat X sehingga:

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

Saya sangat ragu apakah mungkin untuk menyelesaikan persamaan ini menggunakan matematika. Ini adalah masalah pengkodean yang saya temui 3 tahun yang lalu dan bahkan sekarang saya tidak bisa menyelesaikannya sendiri.

Kode saya sejauh ini: (ini adalah solusi brute force)

#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
sumber
11
Jika Anda membaca sedikit tentang eksklusif atau Anda harus menemukan kesetaraan aljabar a xor b = a + b mod 2. Cobalah untuk memikirkan kesetaraan itu sebentar.
Beberapa programmer Bung
16
@Someprogrammerdude Itu jika a dan b adalah variabel Boolean, yaitu 0 atau 1, dan xor adalah Boolean xor. Apa hubungannya dengan bitwise xor?
John Kugelman
1
fwiw, saya pikir menggunakan brute force di sini adalah cara untuk pergi kecuali jika Anda ingin menulis sesuatu yang dapat membuktikan persamaan yang lebih umum. Pertimbangkan bahwa Anda harus menguji kode Anda untuk memastikan bahwa itu benar dan yang termudah adalah dengan menguji terhadap brute force algoritma, tetapi kemudian Anda dapat menggunakan brute force di tempat pertama. Di sisi lain menerapkan matematika pada akhirnya akan membuatnya tidak perlu menjalankan kode apa pun.
idclev 463035818
1
@ Molbdnilo Oh, salah satu komentar menyarankan bahwa xor b = a + b mod 2 dan saya pikir itu juga disebut bilangan bulat. Saya akan menghapus bagian dari posting saya.
AAaAa
1
@JohnKugelman Maksudnya mod 2seperti dalam matematika (mod 2), yaitu 3 === 7 (mod 2). Intinya adalah Anda dapat menemukan persamaan untuk bit pertama X, kemudian pergi ke bit berikutnya di mana (dengan menghargai carry) Anda mendapatkan persamaan untuk bit kedua, dll, seperti jawaban Daniel.
Max Langhof

Jawaban:

45

Catat itu A + X == (A xor X) + ((A and X)<<1). Begitu:

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

Dan kita mempunyai:

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

Jika kondisi terpenuhi, untuk setiap bilangan bulat Y yang tidak memiliki bit yang diatur dalam A, (((A - B) >> 1) atau Y) adalah solusi. Jika Anda hanya menginginkan satu solusi, Anda dapat menggunakan ((A - B) >> 1), di mana Y = 0. Jika tidak ada solusi.

int solve(int a, int b){
    int x = (a - b) >> 1;
    if ((a ^ x) == b + x)
        return x;
    else
        return ERROR;
}
pengguna23013
sumber
15
+1. Ini dengan mencatat bahwa A xor X"tambahan tanpa membawa", dan ((A and X)<<1)"bawa tambahan". Karena A + X"penambahan dengan carry", persamaan pertama masuk akal.
justhalf
3
(A and X)<<1pada dasarnya 2*(A and X)dan karena ini sama dengan A-Bitu mengatakan bahwa masalahnya mungkin memiliki solusi hanya jika A dan B keduanya ganjil atau keduanya peristiwa.
Aksioma
1
Saya pikir itu ada hubungannya dengan pengurangan tetapi saya tidak sampai pada waktunya.
SS Anne
38

Ini tidak terlalu sulit, Anda hanya perlu berpikir kecil: misalkan kita sedang menulis A, Bdan Xdalam biner dan Aᵢadalah nilai yang sesuai dengan bit 2 right paling kanan .

Kita tahu bahwa: Aₒ ⊕ Xₒ = Bₒ + Xₒ.

Mari kita gunakan contoh untuk menemukan cara mengevaluasi itu: A = 15 dan B = 6. Konversi ke biner:

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

Sekarang kami memiliki beberapa kemungkinan. Mari kita menganalisis bit paling kanan dari A dan B:

1  d = 0 + d

Kita tahu itu dhanya 0 atau 1, jadi:

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)

Terlihat bahwa XOR berperilaku seperti jumlah biner (dengan perbedaan bahwa XOR tidak membuat carryover untuk jumlah bit berikutnya):

    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

jadi tidak akan selalu mungkin untuk menemukan X yang memuaskan A ⊕ X = B + X, karena tidak ada nilai dyang memuaskan 1 + d = 0 + d.

Bagaimanapun, jika X ada, Anda bisa mengetahuinya dengan cara ini, dari kanan ke kiri, mencari sedikit demi sedikit.


CONTOH LENGKAP KERJA

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 

Di sini, keduanya d = 0 dan d = 1 berlaku, lalu apa? Kita perlu memeriksa bit selanjutnya. Misalkan 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)

jadi dalam kasus ini, d harus 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

tapi bagaimana dengan b? kita perlu memeriksa bit berikutnya, seperti biasa:

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)

dan sekarang, untuk 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

di sini abisa 0 dan 1, tetapi harus 0, untuk menghindari akumulasi dalam jumlah B + X.

Kemudian,, X = 0 1 0 0dengan demikian X = 4.


KODE

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

Anda bisa mengujinya di sini .

Daniel
sumber