A xor X = B + X için bir çözüm bulma algoritması


46

A ve B tamsayısı verildiğinde, X tamsayısını bulun, böylece:

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

Bu denklemi matematik kullanarak çözmenin mümkün olduğundan şüpheliyim. Bu, 3 yıl önce karşılaştığım bir kodlama problemi ve şimdi bile bunu kendim çözemiyorum.

Kodum şu ana kadar: (bu kaba kuvvet çözümü)

#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
Eğer münhasır hakkında biraz daha okursanız veya cebirsel denkliği bulmalısınız a xor b = a + b mod 2. Bir süre bu denkliği düşünmeye çalışın.
Bazı programcı dostum

16
@Someprogrammerdude Bu, a ve b'nin Boole değişkenleri, yani 0 veya 1 ve xor , bir Boolean xor ise. Bitsel xor ile bağlantı nedir?
John Kugelman

1
fwiw, daha genel denklemleri kanıtlayabilecek bir şey yazmak istemediğiniz sürece burada kaba kuvvet kullanmanın yolunun olduğunu düşünüyorum. Doğru ve en kolayının bir kaba kuvvet algoritmasına karşı test etmek için kodunuzu test etmeniz gerektiğini düşünün, ancak o zaman kaba kuvveti ilk etapta kullanabilirsiniz. Öte yandan matematik uygulamak sonunda herhangi bir kod çalıştırmayı gereksiz hale getirecektir.
idclev 463035818

1
@molbdnilo Oh, yorumlardan biri xor b = a + b mod 2 olduğunu ve bunun da tamsayılara atıfta bulunduğunu düşündü. Yazımın o kısmını kaldıracağım.
AAaAa

1
@JohnKugelman mod 2Matematiksel (mod 2), yani 3 === 7 (mod 2) ' de olduğu anlamına geliyordu . Mesele şu ki, X'in ilk biti için bir denklem keşfedebilir, sonra Daniel'in cevabı gibi ikinci bit için bir denklem aldığınız bir sonraki bite geçebilirsiniz.
Max Langhof

Yanıtlar:


45

Unutmayın A + X == (A xor X) + ((A and X)<<1). Yani:

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

Ve elimizde:

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

Koşul karşılanırsa, A'da ayarlanmış bitleri olmayan herhangi bir Y tamsayısı için, (((A - B) >> 1) veya Y) bir çözümdür. Sadece bir çözüm istiyorsanız, ((A - B) >> 1) kullanabilirsiniz, burada Y = 0'dır. Aksi takdirde çözüm yoktur.

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

15
+1. Bu, A xor X"taşıma olmadan ekleme" olduğunu ve "ekleme ile taşıma" olduğunu belirtmektir ((A and X)<<1). Yana A + X"taşıma ile ilave" dir, ilk denklem mantıklı.
justhalf

3
(A and X)<<1temel 2*(A and X)olarak eşittir ve A-Bbu eşittir , sorunun sadece A ve B'nin hem tek hem de her iki olay olması durumunda bir çözümü olabileceğini söyler.
axiac

1
Çıkarma ile ilgili bir şey olacağını düşündüm ama buna zamanında gelmedim.
SS Anne

38

Biz yazıyoruz varsayalım: Bu sadece küçük düşünmek gerekir, çok zor değil A, Bve Xikili ve Aᵢsağdaki 2 tekabül değerdir bit.

Bunu biliyoruz: Aₒ ⊕ Xₒ = Bₒ + Xₒ.

Bunu nasıl değerlendireceğinizi keşfetmek için bir örnek kullanalım: A = 15 ve B = 6. İkili biçime dönüştürme:

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

Şimdi bazı olasılıklarımız var. A ve B'nin en sağdaki bitlerini analiz edelim:

1  d = 0 + d

dBunun sadece 0 veya 1 olabileceğini biliyoruz , bu yüzden:

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'un ikili toplam gibi davrandığı dikkat çekicidir (XOR'un bir sonraki bit toplamı için bir aktarım yaratmaması farkı ile):

    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

o karşılar bir X bulmak her zaman mümkün olmayacaktır böylece A ⊕ X = B + X, olmadığından bir değer dtatmin olduğunu 1 + d = 0 + d.

Her neyse, X varsa, bu şekilde, sağdan sola, biraz yavaş bulabilirsiniz.


ÇALIŞMA TAM ÖRNEĞİ

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 

Burada, hem d = 0 hem de d = 1 geçerlidir, o zaman ne? Bir sonraki biti kontrol etmeliyiz. D = 1 olduğunu varsayalım:

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)

bu durumda d, 0 olmalıdır.

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

Peki ya b? her zamanki gibi bir sonraki biti kontrol etmeliyiz:

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)

ve şimdi 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

burada a0 ve 1 olabilir, ancak toplamda bir aktarmayı önlemek için 0 olmalıdır B + X.

Daha sonra, X = 0 1 0 0X = 4 olur.


KOD

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

Burada test edebilirsiniz .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.