Что такое "дополнение 2"?

Я на курсе компьютерных систем и был борясь, частично, с дополнение. Я хочу понять это, но все, что я прочитал, не объединило картину для меня. Я читал статья в Википедии и различные другие статьи, в том числе мой текст книги.

следовательно, я хотел начать этот сообщество wiki post, чтобы определить, что такое дополнение, как его использовать и как он может влияет на числа во время таких операций, как приведения (от подписанного до неподписанного и наоборот), битовые операции и операции битового сдвига.

на что я надеюсь-это четкое и краткое определение это легко понять программист.

17 ответов


дополнение Two-это умный способ хранения целых чисел, так что общие математические задачи очень просты в реализации.

чтобы понять, вы должны думать о числах в двоичном формате.

это в основном говорит,

  • для нуля используйте все 0.
  • для целых положительных чисел начните подсчет, максимум с 2(количество бит - 1)-1.
  • для отрицательных чисел, то же самое, но поменяйте роль 0 и 1 (поэтому вместо того, чтобы начинать с 0000, начните с 1111 - это часть "дополнения").

давайте попробуем это с мини-байтом из 4 бит (мы назовем его клев - 1/2 байта).

  • 0000 - ноль
  • 0001 один
  • 0010 два
  • 0011 - три
  • 0100 до 0111 - от четырех до семи

это все, что мы можем сделать позитивы. 23-1 = 7.

негатив:

  • 1111 - отрицательная
  • 1110 - минус два
  • 1101 - минус три
  • 1100 to 1000 - минус четыре-минус восемь

обратите внимание, что вы получаете одно дополнительное значение для негативов (1000 = -8), что вы не для позитива. Это потому что 0000 используется для нуля. Это можно рассматривать как количество Линия компьютеры.

различение положительных и отрицательных чисел

при этом Первый БИТ получает роль бита" знак", так как его можно использовать для различения положительных и отрицательных десятичных значений. Если самый значительный бит 1, тогда двоичный файл можно назвать отрицательным, где, как будто самый значительный бит (самый левый) -0, вы можете сказать, что десятичное значение является положительным.


интересно, можно ли это объяснить лучше, чем статья в Википедии.

основная проблема, которую вы пытаетесь решить с представлением дополнения two, - это проблема хранения отрицательных целых чисел.

сначала рассмотрим целое число без знака, хранящееся в 4 битах. Вы можете иметь следующее

0000 = 0
0001 = 1
0010 = 2
...
1111 = 15

они без знака, потому что нет никаких указаний на то, являются ли они отрицательными или положительными.

знак величины и превышения Нотация

для хранения отрицательных чисел вы можете попробовать несколько вещей. Во - первых, вы можете использовать обозначение величины знака, которое назначает Первый БИТ как бит знака для представления + / - и остальные биты для представления величины. Итак, снова используя 4 бита и предполагая, что 1 означает - и 0 означает +, тогда у вас есть

0000 = +0
0001 = +1
0010 = +2
...
1000 = -0
1001 = -1
1111 = -7

Итак, вы видите проблему там? У нас есть положительный и отрицательный 0. Большая проблема заключается в сложении и вычитании двоичных чисел. Схемы для добавления и вычитание с использованием величины знака будет очень сложным.

что это

0010
1001 +
----

?

другая система лишние нотации. Вы можете хранить отрицательные числа, вы избавляетесь от двух нулей, но сложение и вычитание остаются трудными.

Итак, приходит дополнение два. Теперь вы можете хранить положительные и отрицательные целые числа и выполнять арифметику с относительной легкостью. Существует несколько методов преобразования числа в два дополнение. Вот один.

преобразовать Decimal в дополнение к двум

  1. преобразовать число в двоичный (игнорировать знак на данный момент) например, 5 и -5 это является 0101 0101

  2. если число является положительным числом, то вы сделали. например, 5-это 0101 в двоичной системе счисления, используя два дополнения.

  3. если число отрицательное, то

    3.1 найти дополнение (инвертировать 0 и 1) например, -5 является 0101 так нахождение дополнения 1010

    3.2 добавить 1 к дополнению 1010 + 1 = 1011. Таким образом, -5 в дополнении к двум-1011.

Итак, что, если вы хотите сделать 2 + (-3) в двоичном формате? 2 + (-3) равно -1. Что бы вам пришлось делать, если бы вы использовали величину знака для добавления этих чисел? 0010 + 1101 = ?

используя дополнение two, подумайте, насколько это было бы легко.

 2  =  0010
 -3 =  1101 +
 -------------
 -1 =  1111

преобразование дополнения Two в Decimal

преобразование 1111 в decimal:

  1. число начинается с 1, поэтому оно отрицательное, поэтому мы находим дополнение 1111, которое равно 0000.

  2. добавьте 1 к 0000, и мы получим 0001.

  3. преобразовать 0001 в десятичный, что равно 1.

  4. применить знак = -1.

Тада!


Как и большинство объяснений, которые я видел, выше ясно, как работать с дополнением 2, но на самом деле не объясняют, что они are математически. Я постараюсь сделать это, по крайней мере, для целых чисел, и я сначала покрою некоторый фон, который, вероятно, знаком.

вспомните, как это работает для decimal:
2345
- это способ записи
2 × 103 + 3 × 102 + 4 × 101 + 5 × 100.

таким же образом, двоичный-это способ записи чисел, используя только 0 и 1 следуя той же общей идее, но заменяя эти 10 выше на 2s. Затем в двоичном формате,
1111
- это способ записи
1 × 23 + 1 × 22 + 1 × 21 + 1 × 20
и если вы это выясните, это окажется равным 15 (база 10). Это потому, что это
8+4+2+1 = 15.

Это все хорошо и хорошо для положительных чисел. Это даже работает для отрицательных чисел, если вы готовы просто вставить знак минус перед ними, как люди делают с десятичными числами. Это можно сделать даже в компьютерах, но я не видел такого компьютера с начала 1970-х годов. Я оставлю причины для другого. обсуждение.

для компьютеров оказывается более эффективным использовать дополнение представление отрицательных чисел. И вот что часто упускают из виду. Дополняющие обозначения включают в себя какое-то обращение цифр числа, даже подразумеваемых нулей, которые предшествуют нормальному положительному числу. Это неудобно, потому что возникает вопрос: все? Это может быть бесконечное количество цифр.

к счастью, компьютеры не представляют бесконечности. Числа ограничены определенной длиной (или шириной, если вы предпочитаете). Итак, вернемся к положительным двоичным числам, но с определенным размером. Для этих примеров я буду использовать 8 цифр ("бит"). Таким образом, наше двоичное число действительно будет
00001111
или
0 × 27 + 0 × 26 + 0 × 25 + 0 × 24 + 1 × 23 + 1 × 22 + 1 × 21 + 1 × 20

чтобы сформировать отрицательное дополнение 2, мы сначала дополняем все (двоичные) цифры, чтобы сформировать
11110000
и добавьте 1 в форму
11110001
но как мы должны понимать, что это означает -15?

ответ заключается в том, что мы меняем значение бита высокого порядка ( слева). Этот бит будет 1 для всех отрицательных чисел. Изменение будет заключаться в изменении знака его вклада в значение числа, в котором он появляется. Так что теперь наш!--1-->11110001 понимается как представляющий
-1 × 27 + 1 × 26 + 1 × 25 + 1 × 24 + 0 × 23 + 0 × 22 + 0 × 21 + 1 × 20
обратите внимание, что "-" перед этим выражением? Это означает, что знаковый бит несет вес -27, то есть -128 (база 10). Все остальные позиции сохраняют тот же вес, что и в беззнаковых двоичных числах.

разработка нашего -15, это
-128 + 64 + 32 + 16 + 1
попробуйте на калькуляторе. это -15.

из трех основных способов, которые я видел отрицательные числа, представленные в компьютерах, дополнение 2 выигрывает руки вниз для удобства в общем использовании. Она хоть и странная,. Поскольку он двоичный, должно быть четное количество возможных битовых комбинаций. Каждое положительное число может быть сопряжено с его отрицательным, но есть только один ноль. Отрицание нуля дает ноль. Итак, есть еще одна комбинация, число с 1 в знаке бит и 0 везде. Соответствующее положительное число не будет вписывается в число используемых битов.

Что еще более странно в этом числе, так это то, что если вы попытаетесь сформировать его положительный, дополняя и добавляя один, вы получите тот же отрицательный номер обратно. Кажется естественным, что ноль сделал бы это, но это неожиданно и совсем не то поведение, к которому мы привыкли, потому что компьютеры в стороне, мы обычно думаем о неограниченном количестве цифр, а не об этой арифметике фиксированной длины.

Это похоже на вершину айсберга странностей. Под поверхностью есть еще больше, но этого достаточно для обсуждения. Вероятно, вы могли бы найти больше, если вы исследуете "переполнение" для арифметики с фиксированной точкой. Если вы действительно хотите попасть в него, вы также можете исследовать "модульную арифметику".


дополнение 2 очень полезно для поиска значения двоичного файла, однако я подумал о гораздо более сжатом способе решения такой проблемы (никогда не видел, чтобы кто-то еще опубликовал его):

возьмите двоичный файл, например: 1101, который [предполагая, что пробел " 1 " является знаком] равен -3.

используя дополнение 2, мы сделаем это...флип 1101 в 0010...добавить 0001 + 0010 ===> дает нам 0011. 0011 в положительном двоичном коде = 3. поэтому 1101 = -3!

что я понял:

вместо всего листать и добавлять, вы можете как раз сделать основной метод для разрешать для положительного бинарного (допустим 0101) (23 * 0) + (22 * 1) + (21 * 0) + (20 * 1) = 5.

Сделайте точно такую же концепцию с отрицательным!(с небольшим поворотом)

возьмите 1101, например:

для первое число вместо 23 * 1 = 8, do - (23 * 1) = -8.

тогда продолжайте, как обычно, делать -8 + (22 * 1) + (21 * 0) + (20 * 1) = -3


представьте, что у вас есть конечное число битов/тритов/цифр/что угодно. Вы определяете 0 как все цифры, являющиеся 0, и естественно считаете вверх:

00
01
02
..

В конце концов вы переполнитесь.

98
99
00

мы имеем 2 числа и можем представить все числа от 0 до 100. Все эти цифры положительные! Предположим, мы тоже хотим представить отрицательные числа?

что у нас действительно есть цикл. Число перед 2 равно 1. Номер 1-это 0. Количество до 0 есть... 99.

Итак, для простоты предположим, что любое число свыше 50 отрицательно. "0" до "49" составляют от 0 до 49. "99" - это -1, "98" находится в -2, ... "50" - это -50.

данное представление десять дополнения. Компьютеры обычно используют дополнение, что то же самое, за исключением использования битов вместо цифр.

хорошая вещь о дополнении ten - это дополнение работает. Вы не нужно сделать что-нибудь особенное, чтобы добавить положительные и отрицательные числа!


два дополнения обнаруживаются путем добавления одного к 1-му дополнению данного числа. Допустим, мы должны найти дополнение twos 10101 тогда найдите его дополнение, то есть 01010 добавить 1 к этому результату, то есть 01010+1=01011, который является окончательным ответом.


позволяет получить ответ 10 – 12 в двоичной форме, используя 8 бит: То, что мы действительно сделаем, это 10 + (-12)

нам нужно получить комплимент часть 12, чтобы вычесть его из 10. 12 в двоичной 00001100. 10 в двоичной 00001010.

чтобы получить комплимент часть 12 мы просто перевернуть все биты, а затем добавить 1. 12 в двоичном обратном - 11110011. Это также обратный код (дополнение). Теперь нам нужно добавить один, который теперь 11110100.

Так 11110100 является комплимент от 12! Легко, когда ты так думаешь.

теперь вы можете решить вышеуказанный вопрос 10-12 в двоичной форме.

00001010
11110100
-----------------
11111110  

глядя на систему дополнения двух с математической точки зрения, это действительно имеет смысл. В дополнение к Тен идея состоит в том, чтобы по существу "изолировать" разницу.

пример: 63-24 = x

мы добавляем дополнение 24, которое действительно просто (100-24). Так что на самом деле все, что мы делаем, это добавляем 100 по обе стороны уравнения.

теперь уравнение: 100 + 63 - 24 = x + 100, поэтому мы удаляем 100 (или 10 или 1000 или все.)

из-за неудобной ситуации, когда приходится вычитать одно число из длинной цепочки нулей, мы используем систему "уменьшенного дополнения радикса" в десятичной системе, дополнение девяти.

когда нам представляется число, вычитаемое из большой цепочки девяток, нам просто нужно обратить числа.

пример: 99999 - 03275 = 96724

вот почему после дополнения девяти мы добавляем 1. Как вы, наверное, знаете из детства Математика, 9 становится 10 путем "кражи" 1. Таким образом, в основном это просто дополнение ten, которое берет 1 из разницы.

в двоичном коде дополнение двух равно дополнению десяти, в то время как дополнение одного к дополнению девяти. Основное различие заключается в том, что вместо того, чтобы пытаться изолировать разницу с степенями десяти (добавляя 10, 100 и т. д. в уравнение) мы пытаемся изолировать разницу с степенями двух.

именно по этой причине мы инвертируем биты. Просто как наши уменьшаемое-это цепь девяток в десятичной, наши уменьшаемое-это цепочка единиц в двоичной.

пример: 111111 - 101001 = 010110

поскольку цепочки единиц на 1 ниже хорошей степени двух, они "крадут" 1 из разницы, как девять в десятичном.

когда мы используем отрицательные двоичные числа, мы действительно просто говорим:

0000-0101 = x

1111 - 0101 = 1010

1111 + 0000 - 0101 = x + 1111

чтобы "изолировать" x, нам нужно добавить 1, потому что 1111-это один из 10000, и мы удаляем ведущий 1, потому что мы только что добавили его к исходной разнице.

1111 + 1 + 0000 - 0101 = x + 1111 + 1

10000 + 0000 - 0101 = x + 10000

просто удалите 10000 с обеих сторон, чтобы получить x, это базовая алгебра.


многие из ответов до сих пор хорошо объясняют, почему дополнение two используется для представления отрицательного числа, но не говорят нам, что такое число дополнения two, особенно не почему добавляется "1", и на самом деле часто добавляется неправильно.

путаница возникает из-за плохого понимания определения числа дополнения. Дополнение-это недостающая часть, которая сделает что-то полным.

дополнение radix N-значного числа x в radix b, по определение, b^n-x. В двоичном формате 4 представляет собой 100, который имеет 3 цифры (n=3) и радиус 2 (b=2). Таким образом, его дополнение radix-b^n-x = 2^3-4=8-4=4 (или 100 в двоичном коде).

однако в двоичном коде получение дополнения radix не так просто, как получение его уменьшенного дополнения radix, которое определяется как (b^n-1)-y, всего на 1 меньше, чем у дополнения radix. Чтобы получить уменьшенное дополнение radix, вы просто переворачиваете все цифры.

100 - > 011 (уменьшенный (один) радиус дополнение)

чтобы получить дополнение radix (two), мы просто добавляем 1, Как определено определение.

011 +1 ->100 (два дополнения).

теперь с этим новым пониманием давайте рассмотрим пример, приведенный Vincent Ramdhanie (см. выше второй ответ)

/* начало Vincent

преобразование 1111 в decimal:

число начинается с 1, поэтому оно отрицательное, поэтому мы находим дополнение 1111, которое 0000. Добавьте 1 к 0000, и мы получим 0001. Преобразуйте 0001 в десятичное число, которое равно 1. Применять знак = -1. Тада!

конец Винсент */

следует понимать как

число начинается с 1, поэтому оно отрицательное. Таким образом, мы знаем, что это дополнение двойки некоторого значения X. Чтобы найти x, представленное дополнением его двух, нам сначала нужно найти дополнение его 1.

два дополнения x: 1111 одно дополнение x: 1111-1 - >1110; x = 0001, (перевернуть все цифры)

применить знак -, а ответ = - x =-1.


Это умное средство кодирования отрицательных целых чисел таким образом, что примерно половина комбинации битов типа данных зарезервирована для отрицательных целых чисел, а добавление большинства отрицательных целых чисел с соответствующими положительными целыми приводит к переполнению переноса, которое оставляет результат двоичным нулем.

Итак, в дополнении 2, если один равен 0x0001, то -1 равен 0x1111, потому что это приведет к комбинированной сумме 0x0000 (с переполнением 1).


дополнения 2: Когда мы добавим дополнительный с дополнениями 1 числа, мы получим дополнения 2. Например: 100101 это 1 дополнения является 011010 и 2 дополнения-это 011010+1 = 011011 (путем добавления одного с дополнение до 1) для получения дополнительной информации эта статья объясняет это графически.


Мне понравился ответ лавинио, но сдвиг бит добавляет некоторую сложность. Часто есть выбор движущихся битов, уважая бит знака или не уважая бит знака. Это выбор между обработкой чисел как подписанных (от -8 до 7 для кусочка, от -128 до 127 для байтов) или полных беззнаковых чисел (от 0 до 15 для кусочков, от 0 до 255 для байтов).


У меня была такая же проблема пару недель назад. В конце концов я прочитал об этом в интернете из разных источников, пытаясь сложить кусочки вместе, и написал об этом сам, просто чтобы убедиться, что я понял это правильно. Мы используем дополнение two в основном по двум причинам:

  1. чтобы избежать нескольких представлений 0
  2. избежать держать след бита снесите (как в одном дополнении) в случае переполнения.
  3. проведение простых операций, таких как сложение и вычитание становятся легкими.

Если вы хотите более подробное объяснение вопроса под рукой, попробуйте статью, написанную мной здесь. Надеюсь, это поможет!


Я прочитал фантастическое объяснение на Reddit по jng, используя одометр в качестве аналогии.

enter image description here

Это полезное соглашение. Те же схемы и логические операции, которые добавить / вычесть положительные числа в двоичном формате по-прежнему работают на обоих положительных и отрицательные числа, если использовать конвенцию, вот почему это так полезный и вездесущий.

представьте себе одометр автомобиля, он катится по (скажем) 99999. Если вы прирост вы получите 00000 00001. Если вы уменьшите 00000, вы получите 99999 (из-за переката). Если добавить один назад к 99999 он восходит к 00000. Поэтому полезно решить, что 99999 представляет -1. Точно так же очень полезно решить, что 99998 представляет собой -2, и так далее. У вас есть чтобы где-то остановиться, а также по соглашению, верхняя половина чисел считаются отрицательными (50000-99999), а нижняя половина положительной просто постоять за себя (00000-49999). Как результат, верхняя цифра быть 5-9 означает, что представленное число отрицательно, а 0-4 означает, что представленный положительный - точно такой же, как и верхний бит представление знака в двоичном числе дополнения двойки.

понимание этого было трудно для меня тоже. Однажды я получил его и вернулся к перечитайте книги статей и объяснений (интернета не было тогда), оказалось, что многие из тех, кто описывал это, на самом деле не понять это. Я написал учебной книги язык ассемблера после это (который продавался довольно хорошо в течение 10 лет).


ссылка:https://www.cs.cornell.edu / ~tomf/notes/cps104/twoscomp.html

Я инвертировать все биты и прибавить 1. Программно:

  // in C++11
  int _powers[] = {
      1,
      2,
      4,
      8,
      16,
      32,
      64,
      128
  };

  int value=3;
  int n_bits=4;
  int twos_complement = (value ^ ( _powers[n_bits]-1)) + 1;

вы также можете использовать онлайн-калькулятор для вычисления двоичного представления дополнения двух десятичных чисел:http://www.convertforfree.com/twos-complement-calculator/


самый простой ответ:

1111 + 1 = (1)0000. Таким образом, 1111 должен быть -1. То -1 + 1 = 0.

Это идеально, чтобы понять все это для меня.