~ x + ~ y == ~ (x + y) jest zawsze fałszywe?

153

Czy ten kod zawsze daje wynik fałszywy? Obie zmienne są liczbami int ze znakiem uzupełnienia do dwóch.

~x + ~y == ~(x + y)

Wydaje mi się, że powinna istnieć liczba spełniająca warunki. Próbowałem sprawdzić liczby pomiędzy -5000i, 5000ale nigdy nie osiągnąłem równości. Czy istnieje sposób na utworzenie równania, aby znaleźć rozwiązania warunku?

Czy zamiana jednego na drugi spowoduje podstępny błąd w moim programie?

Steve
źródło
6
Chcesz udowodnić czy coś?
Alvin Wong
26
Należy pamiętać, że w przypadku przepełnienia liczb całkowitych ze znakiem jest to technicznie niezdefiniowane zachowanie. Jest więc możliwe, że powróci, truenawet jeśli nigdy nie będą mogli przyjąć ścisłego dopełnienia do dwóch.
Mysticial
1
@AlvinWong tak, wyjaśnienie byłoby miłe
Steve
1
@Steve: Możesz wykazać, że wypróbowałeś wszystkich zwykłych podejrzanych (-1, 0, 1, 2 itd.) We wszystkich kombinacjach, a także swoje próby „rozwiązania” problemu dla małych rozmiarów słów ( trzy bity? cztery bity?). To z pewnością pomogłoby nam przekonać, że nie pomagamy komuś tylko zdobyć coś, na co nie próbowali najpierw zarobić. :)
sarnold
4
@AlexLockwood Kiedy po raz pierwszy opublikowałem pytanie, założyłem, że oznaczenie pytania jako „praca domowa” wymaga od ludzi podania wskazówek, które pomogą mi rozwiązać problem (jak stwierdza opis tagu „praca domowa”), a nie tylko udzielenie odpowiedzi. Dlatego właśnie po prostu zadałem pytanie o problem :)
Steve

Odpowiedzi:

237

Załóżmy dla sprzeczności, że istnieją takie, xa niektóre y(mod 2 n ) takie

~(x+y) == ~x + ~y

Dzięki dopełnieniu do dwóch * wiemy, że

      -x == ~x + 1
<==>  -1 == ~x + x

Uwzględniając ten wynik,

      ~(x+y) == ~x + ~y
<==>  ~(x+y) + (x+y) == ~x + ~y + (x+y)
<==>  ~(x+y) + (x+y) == (~x + x) + (~y + y)
<==>  ~(x+y) + (x+y) == -1 + -1
<==>  ~(x+y) + (x+y) == -2
<==>  -1 == -2

Stąd sprzeczność. Dlatego ~(x+y) != ~x + ~ydla wszystkich xi y(mod 2 n ).


* Warto zauważyć, że na maszynie z własną arytmetyką dopełnień równość faktycznie obowiązuje dla wszystkich xi y. To dlatego, że pod jednym z dopełnieniem, ~x = -x. Zatem ~x + ~y == -x + -y == -(x+y) == ~(x+y).

Alex Lockwood
źródło
47
Oczywiście C nie wymaga takiego zachowania; ponieważ nie wymaga reprezentacji dopełnienia do dwóch.
Billy ONeal
12
Przy okazji, równość jest prawdziwa dla komplementu. Operacja NOT nie jest tak naprawdę zdefiniowana dla liczby w ogóle, więc mieszanie NOT z dodawaniem powoduje różne zachowanie w zależności od reprezentacji liczby.
nhahtdh
9
Można by po prostu powtórzyć problem dla liczb całkowitych bez znaku, a wtedy dopełnienie do dwójki w ogóle nie wchodzi w grę.
R .. GitHub PRZESTAŃ POMÓC W LODZIE
5
Jeszcze prostsze, IMHO: ~x == -(x+1)tak ~(x+y) == ~x + ~yimplikuje -(x+y+1) == -(x+1) + -(y+1)implikuje-1 == -2
BlueRaja - Danny Pflughoeft
7
@BillyONeal, nie martw się, tylko żartowałem i doceniam, że o tym wspomniałeś :). Postawię ci drinka w dniu, w którym napotkam maszynę, która wykonuje arytmetykę dopełnień ... jak to brzmi? haha
Alex Lockwood
113

Dopełnienie do dwóch

W zdecydowanej większości komputerów, jeśli xjest liczbą całkowitą, to -xjest reprezentowane ~x + 1. Równoważnie ~x == -(x + 1). Dokonanie tego podstawienia w swoim równaniu daje:

  • ~ x + ~ y == ~ (x + y)
  • - (x + 1) + - (y + 1) = - ((x + y) + 1)
  • -x - y - 2 = -x - y - 1
  • -2 = -1

co jest sprzecznością, więc ~x + ~y == ~(x + y)zawsze jest fałszywe .


To powiedziawszy, pedanci zwrócą uwagę, że C nie wymaga uzupełnienia do dwóch, więc musimy również rozważyć ...

Dopełnienie

W kod uzupełnień do jedności , -xjest po prostu reprezentowane ~x. Zero jest przypadkiem specjalnym, mając zarówno reprezentacje all-0 ( +0), jak i all-1 ( -0), ale IIRC, C wymaga, +0 == -0nawet jeśli mają różne wzorce bitowe, więc nie powinno to stanowić problemu. Wystarczy podstawić ~z -.

  • ~ x + ~ y == ~ (x + y)
  • -x + (-y) = - (x + y)

co jest prawdą dla wszystkich xi y.

dan04
źródło
13
+1 za odpowiedź, która faktycznie uwzględnia dopełnienie do dwóch i dopełnienie na równym poziomie.
CVn
13
@ dan04, +0 == -0. Wreszcie coś, co ma sens w C. :)
Alex Lockwood
32

Rozważmy tylko skrajny prawy bit z obu xi y(tj. Jeśli x == 13który jest 1101w bazie 2, przyjrzymy się tylko ostatniemu bitowi, a 1) Istnieją cztery możliwe przypadki:

x = 0, y = 0:

LHS: ~ 0 + ~ 0 => 1 + 1 => 10
RHS: ~ (0 + 0) => ~ 0 => 1

x = 0, y = 1:

LHS: ~ 0 + ~ 1 => 1 + 0 => 1
RHS: ~ (0 + 1) => ~ 1 => 0

x = 1, y = 0:

Zostawię to tobie, ponieważ jest to praca domowa (wskazówka: jest taka sama jak poprzednia z zamienionymi x i y).

x = 1, y = 1:

To również zostawię tobie.

Możesz pokazać, że najbardziej prawy bit będzie zawsze różny po lewej i prawej stronie równania, biorąc pod uwagę wszelkie możliwe dane wejściowe, więc udowodniłeś, że obie strony nie są równe, ponieważ mają co najmniej ten jeden odwrócony bit od siebie nawzajem.

Paweł
źródło
27

Jeśli liczba bitów wynosi n

~x = (2^n - 1) - x
~y = (2^n - 1) - y


~x + ~y = (2^n - 1) +(2^n - 1) - x - y =>  (2^n + (2^n - 1) - x - y ) - 1 => modulo: (2^n - 1) - x - y - 1.

Teraz,

 ~(x + y) = (2^n - 1) - (x + y) = (2^n - 1) - x - y.

Dlatego zawsze będą nierówne, z różnicą 1.

Karthik Kumar Viswanathan
źródło
4
@nhahtdh i jak definiujesz ~operację na liczbach o stałej szerokości?
hamstergene
1
Podałem tę odpowiedź z tą liczbą bitów, aby łatwo było skorelować z tym, czego uczy się na zajęciach. Zauważ, że ~ x jest w dużym stopniu zależne od liczby bitów n, użytych do przedstawienia liczby. Dlatego rozsądnie jest trzymać się jednego, próbując zweryfikować to eksperymentalnie.
Karthik Kumar Viswanathan
1
@hamstergene: Wiem, że liczba bitów jest stała, ale chodzi mi o to, że nie musi to być ta liczba (8, 16 itd.).
nhahtdh
1
Są to wartości, dla których łatwo napisać program weryfikujący odpowiedź. Działa dla każdego n, o ile ~ x i ~ y są zapisywane tak, aby pasowały do ​​podanych.
Karthik Kumar Viswanathan
1
@hamstergene: Nie mam problemu z dowodem, tylko że liczby dają fałszywą sugestię, że działa on tylko w tych przypadkach.
nhahtdh
27

Wskazówka:

x + ~x = -1(mod 2 n )

Zakładając, że celem pytania jest sprawdzenie Twojej matematyki (a nie umiejętności czytania specyfikacji C), powinno to doprowadzić Cię do odpowiedzi.

user541686
źródło
2
Tylko na dwóch maszynach uzupełniających. (Standard C tego nie wymaga)
Billy ONeal
12
@Billy: To tak, jakby powiedzieć „tylko dla osób dwuramiennych”.
dan04
2
@ dan04: Nie, nie jest. Chciałbym powiedzieć, że wszystkie podpisane wielkości i ich uzupełnienia zniknęły ze świata. Ale myliłbym się, mówiąc to. Standard C nie pozwala ci na takie założenie; dlatego powiedziałbym, że kod, który zakłada, że ​​jest to zły kod przez większość czasu. (Szczególnie, gdy zwykle istnieją lepsze sposoby na
manipulowanie liczbami ze znakiem niż przekręcanie
10

W dopełnieniu zarówno jednym, jak i dwóch (a nawet w 42-ach) można to udowodnić:

~x + ~y == ~(x + a) + ~(y - a)

Teraz pozwól a = yi mamy:

~x + ~y == ~(x + y) + ~(y - y)

lub:

~x + ~y == ~(x + y) + ~0

Dlatego w uzupełnieniu do dwóch ~0 = -1, to zdanie jest fałszywe.

W uzupełnieniu ~0 = 0, twierdzenie to jest prawdziwe.

ypercubeᵀᴹ
źródło
7

Według książki Dennisa Ritchiego, C nie implementuje domyślnie dopełnienia do dwóch. Dlatego twoje pytanie może nie zawsze być prawdziwe.

user1457474
źródło
5

Niech MAX_INTbędzie wartością int reprezentowaną przez 011111...111(dla dowolnej liczby bitów). Wtedy to wiesz ~x + x = MAX_INTi ~y + y = MAX_INTdlatego będziesz wiedział na pewno, że różnica między ~x + ~ya ~(x + y)jest 1.

Adrian Monk
źródło
5

C nie wymaga implementacji dopełnienia do dwóch. Jednak w przypadku liczb całkowitych bez znaku stosowane są podobne logiki. W tej logice różnice zawsze będą wynosić 1!

user1422551
źródło
3

Oczywiście C nie wymaga takiego zachowania, ponieważ nie wymaga reprezentacji dopełnienia do dwóch. Na przykład ~x = (2^n - 1) - x& ~y = (2^n - 1) - yotrzyma ten wynik.

user1472392
źródło
0

Ach, podstawowa matematyka dyskretna!

Sprawdź prawo De Morgana

~x & ~y == ~(x | y)

~x | ~y == ~(x & y)

Bardzo ważne dla dowodów logicznych!

David Kaczyński
źródło
Po prostu źle. W C + to dodawanie, * mnożenie, a nie wartość logiczna lub lub i.
nalply
Dziękujemy za wskazanie nieprawidłowych operatorów, nalply. Został on teraz zaktualizowany o prawidłowe operatory, chociaż masz rację, ponieważ nie dotyczy oryginalnego pytania.
David Kaczynski
1
Cóż, jeśli prawda jest równa jeden, a fałsz równa się zero, to + i * zachowują się dokładnie tak, jak lub i, a ponadto dopełnienie do dwóch zachowuje się jak nie, a zatem prawo ma zastosowanie.
a1an
Dziękuję za zwrócenie uwagi, a1an. Próbowałem się zastanowić, jak prawa De Morgana mogą nadal mieć zastosowanie do pierwotnego pytania, ale minęło kilka lat, odkąd studiowałem programowanie w C lub matematykę dyskretną.
David Kaczynski