~ x + ~ y == ~ (x + y) завжди хибно?


153

Чи завжди цей код оцінюється як хибний? Обидві змінні - це два підписані доповнення.

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

Я відчуваю, що має бути якесь число, яке задовольняє умовам. Я спробував перевірки чисел між -5000і , 5000але ніколи не досягається рівність. Чи є спосіб скласти рівняння для пошуку розв’язків умови?

Чи буде обмін одним на інший викликати підступну помилку в моїй програмі?


6
Ви хочете довести чи щось таке?
Альвін Вонг

26
Майте на увазі, що у випадках підписаного цілого переповнення це технічно невизначена поведінка. Тож можливо повернутись, trueнавіть якщо вони ніколи не можуть припускати суворої доповнення двох.
Містичний

1
@AlvinWong так, пояснення було б непогано
Стів

1
@Steve: Ви можете продемонструвати, що ви судили всіх звичних підозрюваних (-1, 0, 1, 2 тощо) у всіх комбінаціях, а також ваші спроби "вирішити" проблему для малих розмірів слів ( три біти? чотири біта?). Це безумовно допомогло б переконати нас у тому, що ми не просто допомагаємо комусь отримати щось, на чому спочатку не намагалися заробити. :)
sarnold

4
@AlexLockwood Коли я вперше опублікував це запитання, я припустив, що тегнути це питання як "домашнє завдання" просить людей надати підказки, щоб допомогти мені вирішити проблему (як зазначено в описі тегу "домашнє завдання"), а не просто давати відповіді. Ось чому я просто задав питання проблеми :)
Стів

Відповіді:


237

Припустимо, для суперечності існують деякі xта деякі y(mod 2 n ) такі, що

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

За доповненням двох * ми знаємо, що,

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

Зазначаючи цей результат, ми маємо,

      ~(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

Отже, суперечність. Тому ~(x+y) != ~x + ~yдля всіх xі y(mod 2 n ).


* Цікаво зазначити, що на машині з арифметикою доповнення, рівність насправді справедлива для всіх xі y. Це відбувається тому , що під своїм комплементом ~x = -x. Таким чином, ~x + ~y == -x + -y == -(x+y) == ~(x+y).


47
Звичайно, С не вимагає такої поведінки; оскільки це не вимагає представлення комплементу двох.
Біллі ONeal

12
До речі, рівність стосується доповнення. Операція NOT насправді не визначається для числа загалом, тому змішування NOT з додаванням призводить до різної поведінки залежно від представлення числа.
nhahtdh

9
Можна просто перезапустити проблему, щоб бути цілими без підписів, і тоді доповнення двійок взагалі не вступають у гру.
R .. GitHub СТОП ДОПОМОГАТИ ЛІС

5
Ще простіше, ІМХО:, ~x == -(x+1)так ~(x+y) == ~x + ~yмається на -(x+y+1) == -(x+1) + -(y+1)увазі-1 == -2
BlueRaja - Danny Pflughoeft

7
@BillyONeal, не хвилюйся, я тільки жартував і ціную, що ти це згадав :). Я куплю тобі напій у той день, коли я зустріну машину, яка виконує доповнення арифметики ... як це звучить? ха-ха
Алекс Локвуд

113

Доповнення двох

На переважній більшості комп'ютерів, якщо xце ціле число, то -xпредставлено як ~x + 1. Рівнозначно , ~x == -(x + 1). Внесення цієї субституції у ваше рівняння дає:

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

що суперечить, тому ~x + ~y == ~(x + y)завжди хибне .


При цьому педанти зазначають, що C не потребує доповнення двох, тому ми також повинні врахувати ...

Один доповнення

У доповненні , -xпросто представляється як ~x. Нуль - це особливий випадок, який має представлення як усіх-0 ( +0), так і всіх-1 ( -0), але IIRC, C вимагає +0 == -0навіть якщо вони мають різні бітові структури, тому це не повинно бути проблемою. Просто замінити ~на -.

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

що вірно для всіх xі y.


13
+1 для відповіді, яка насправді вважає доповнення двох та однакові доповнення на рівній основі.
CVn

13
@ Dan04, +0 == -0. Нарешті щось, що має сенс у C. :)
Алекс Локвуд

32

Розглянемо лише самий крайній біт обох xі y(IE. Якщо він x == 13знаходиться 1101в базі 2, ми розглянемо лише останній біт, а 1) Тоді є чотири можливі випадки:

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:

Я залишаю це за вами, оскільки це домашнє завдання (підказка: це те саме, що і попереднє з x і y замінено).

x = 1, y = 1:

Я також залишу цей варіант.

Ви можете показати, що правий біт завжди буде різний на лівій та правій частині рівняння з урахуванням будь-якого можливого введення, тому ви довели, що обидві сторони не рівні, оскільки у них є принаймні той біт, який перевернутий один від одного.


27

Якщо кількість бітів дорівнює 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.

Тепер,

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

Отже, вони завжди будуть нерівними з різницею в 1.


4
@nhahtdh і як ви визначаєте ~операцію над нефіксованими номерами ширини?
хамстерген

1
Я дав цю відповідь з цією кількістю біт, щоб було легко співвіднести з тим, що викладають на заняттях. Зауважимо, що ~ x сильно залежить від кількості бітів, n, що використовується для представлення числа. Тому доцільно дотримуватися одного, намагаючись перевірити це експериментально.
Karthik Kumar Viswanathan

1
@hamstergene: Я знаю, що кількість бітів є фіксованою, але моя думка полягає в тому, що вона не повинна бути такою кількістю (8, 16 і т.д.).
nhahtdh

1
Це значення, на які легко написати програму для перевірки відповіді. Він працює для будь-якого n, доки записані ~ x і ~ y, щоб відповідати заданому.
Karthik Kumar Viswanathan

1
@hamstergene: У мене немає проблем із доказом, лише те, що цифри дають помилковий сенс, що він працює лише у цих випадках.
nhahtdh

27

Підказка:

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

Якщо припустити, що мета питання - це перевірка вашої математики (а не ваших навичок читання-С-специфікацій), це повинно дати вам відповідь.


2
Тільки на двох машинах для доповнення. (Стандарт C цього не вимагає)
Біллі ONeal

12
@Billy: Це як би сказати "лише для дворуких людей".
dan04

2
@ dan04: Ні, це не так. Я хотів би сказати, що всі підписані масштаби та ті, що доповнюють уявлення, пішли зі світу. Але я помиляюся, кажучи це. Стандарт C не дозволяє робити це припущення; тому я б сказав, що кодекс робить таке припущення, що більшість часу це неправильний код. (Особливо, коли зазвичай є кращі способи возитися з підписаними номерами, ніж
подвійне подвійне

10

І в доповненнях одного, і двох (і навіть у 42-х) це можна довести:

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

Тепер давайте a = yі маємо:

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

або:

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

Тому в двох доповненнях це ~0 = -1, судження є хибним.

Доповнюючи це ~0 = 0, судження є істинним.


7

Згідно з книгою Денніса Річі, С не реалізує доповнення двох за замовчуванням. Тому ваше запитання не завжди може бути правдивим.


5

Нехай це MAX_INTбуде int, представлений символом 011111...111(наскільки багато бітів існує). Тоді ви це знаєте, ~x + x = MAX_INTі ~y + y = MAX_INTтому ви точно знатимете, що різниця між ~x + ~yі ~(x + y)є 1.


5

C не вимагає, щоб доповнення двох було те, що реалізоване. Однак для непідписаних цілих чисел застосовується аналогічна логіка. Відмінності завжди будуть 1 за цією логікою!


3

Звичайно, C не вимагає такої поведінки, оскільки не вимагає представлення комплементу двох. Наприклад, ~x = (2^n - 1) - x& ~y = (2^n - 1) - yотримає цей результат.


0

Ах, фундаментальна дискретна математика!

Ознайомтеся із законом Де Моргана

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

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

Дуже важливі для булевих доказів!


Просто неправильно. У C + є додавання, * множення, а не булеве або, і.
nalply

Дякую за те, що ви вказали на некоректних операторів, натільно. Зараз він оновлювався з правильними операторами, хоча ви правильні, оскільки це не стосується початкового запитання.
Давид Качинський

1
Що ж, якщо істина одна, а помилка - нуль, то + і * поводяться точно так, як і і, і, тим більше, що доповнення двох поводиться як ні, отже, закон застосовується.
a1an

Дякую, що вказали на це, a1an. Я намагався подумати про те, як Закони Де Моргана ще можуть бути застосовними до початкового питання, але минуло кілька років, як я вивчав або програмування на С, або дискретну математику.
Давид Качинський
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.