Как процессор выполняет вычитание?

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

Скажем, А = 5, В = -2. Предполагая, что A и B являются 4-байтовыми, как ЦП выполняет сложение A + B?

Я понимаю, что A будет иметь знаковый бит (MSB) как 0, чтобы обозначить положительное значение, а B будет иметь знаковый бит как 1, чтобы обозначить отрицательное целое число.

Теперь, когда в программе C ++ я хочу напечатать A + B, модуль сложения ALU (арифметико-логическое устройство) сначала проверяет знаковый бит, а затем решает выполнить вычитание, а затем следует процедуре вычитания. Как выполняется вычитание, будет моим следующим вопросом.

A = 5
B = 2

Я хочу сделать A - B. Компьютер возьмет дополнение 2 к B и добавит дополнение A + 2 к B и вернет это (после отбрасывания лишнего бита слева)?

A = 2
B = 5

сделать A - B. Как поступит в этом случае компьютер?

Я понимаю, что любая условная логика if-then и т. д. будет выполняться аппаратно внутри ALU. вычисление дополнения 2s и т. д., отбрасывая дополнительный бит, все будет выполняться аппаратно внутри ALU. Как выглядит этот компонент ALU?


person xyz    schedule 26.04.2011    source источник
comment
ALU выглядит примерно так: en.wikipedia.org/wiki/   -  person Johan Kotlinski    schedule 26.04.2011
comment
Отрицательные числа являются дополнением до 2 соответствующего положительного числа, а не просто изменением бита знака.   -  person phkahler    schedule 26.04.2011


Ответы (5)


Вся причина, по которой мы используем дополнение до двойки, заключается в том, что сложение одинаково независимо от того, являются ли числа положительными. или отрицательный - нет особых случаев для рассмотрения, как в случае с дополнением до 1 или Представления signed-magnitude.

Таким образом, чтобы найти A-B, мы можем просто инвертировать B и добавить; то есть мы находим A + (-B), и, поскольку мы используем 2-е дополнение, мы не беспокоимся, является ли (-B) положительным или отрицательным, потому что алгоритм сложения работает одинаково в любом случае.

person BlueRaja - Danny Pflughoeft    schedule 26.04.2011
comment
в дополнении до 1 также нет особых случаев для рассмотрения. Вы просто добавляете 2 числа и добавляете перенос. Только знаковая величина должна заботиться о знаковом бите - person phuclv; 23.05.2019
comment
Обратите внимание, что некоторые ISA (например, x86) имеют вывод флага переноса, который устанавливается, если реальное вычитание будет иметь заимствование, а не гипотетическое A + (-B) сложение. Эта возможность реализации не меняет того факта, что (-1) - (-2) (т.е. 0xFF - 0xFE) приводит к CF=0. В ARM все наоборот: после вычитания флаг C является результатом !borrow, и инструкция ARM sbc ведет себя соответственно. - person Peter Cordes; 02.12.2019

Подумайте о двух или трех битах, а затем поймите, что эти вещи масштабируются до 32, 64 или сколько угодно бит.

Во-первых, давайте начнем с десятичной

 99
+22
===

Чтобы сделать это, у нас будет что-то вроде "Carry the one's".

11
 99
+22
===
121

9 плюс 2 равно 1 нести единицу, 1 плюс 9 плюс 2 равно 2 нести единицу...

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

Поскольку вы использовали 5 и 2, давайте сделаем 4-битную двоичную математику.

 0101
+0010
=====
 0111

Нам не нужно было продолжать это, но вы можете видеть, что математика сработала, 5 + 2 = 7.

И если мы хотим добавить 5 и -2

11
 0101
+1110
=====
 0011

И ответ 3, как и ожидалось, не очень удивительно, но у нас было выносливость. И поскольку это было сложение с минусовым числом в дополнении до двух, все это работало, тогда не было знакового бита if, дополнение до двух делает это так, что нам все равно, просто скармливайте сумматору два операнда.

Теперь, если вы хотите сделать тонкое различие, что, если вы хотите вычесть 2 из 5, вы выбираете инструкцию вычитания, а не сложения. Ну, мы все узнали, что отрицание в двойном дополнении означает инвертирование и добавление единицы. И мы видели выше, что сумматору с двумя входами действительно нужен третий вход для переноса, чтобы его можно было каскадировать до такой ширины, какой должен быть сумматор. Таким образом, вместо выполнения двух операций сложения, инвертирования и добавления 1, являющегося первым добавлением реального сложения, все, что нам нужно сделать, это инвертировать и установить перенос:

Поймите, что нет никакой логики вычитания, она добавляет негатив от того, что вы ей кормите.

    v this bit is normally zero, for a subtract we set this carry in bit
11 11
 0101 five
+1101 ones complement of 2
=====
 0011

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

Существует два вида переполнения: без знака и со знаком. Без знака просто это бит переноса. Переполнение со знаком связано со сравнением бита переноса в столбце msbit с битом переноса для этого столбца. Для нашей математики выше вы видите, что перенос и перенос в этом столбце msbit одинаковы, оба равны единице. И мы узнали путем проверки, что в 4-битной системе достаточно места для правильного представления чисел +5, -2 и +3. 4-битная система может представлять числа от +7 до -8. Таким образом, если вы добавите 5 и 5 или -6 и -3, вы получите переполнение со знаком.

01 1
 0101
+0101
=====
 1010

Поймите, что ОДИНАКОВАЯ логика сложения используется для математики со знаком и без знака, это зависит от вашего кода, а не от логики, чтобы виртуально определить, считались ли эти биты двойным дополнением со знаком или без знака.

В приведенном выше случае 5 + 5 вы видите, что перенос в столбце msbit равен 1, но перенос равен 0, что означает, что флаг V, знаковый флаг переполнения, будет установлен логикой. В то же время перенос того бита, который является флагом переноса C, не будет установлен. Если подумать, 4 бита без знака могут содержать числа от 0 до 15, поэтому 5 + 5 = 10 не переполняется. Но если подумать, 4 бита со знаком могут содержать от +7 до -8, а 5 + 5 = 10 — это переполнение со знаком, поэтому установлен флаг V.

если/когда у вас есть сложение с инструкцией переноса, они берут ту же самую схему сумматора, и вместо того, чтобы подавать перенос в ноль, ему подается флаг переноса. Аналогично вычитанию с заимствованием, вместо подачи переноса в 1 ввод переноса представляет собой либо 1, либо 0 в зависимости от состояния флага переноса в регистре состояния.

Умножение - это совсем другая история, двоичное число делает умножение намного проще, чем при использовании десятичной математики, но у вас ДОЛЖНЫ быть разные инструкции умножения без знака и со знаком. А деление — это отдельный зверь, вот почему в большинстве наборов инструкций нет деления. У многих нет умножения из-за количества гейтов или часов, которые он сжигает.

person old_timer    schedule 27.04.2011

Вы немного ошиблись в битовой части знака. Это не просто бит знака — каждое отрицательное число преобразуется в дополнение до 2. Если вы пишете:

B = -2

Компилятор при компиляции в бинарник сделает так:

1111 1111 1111 1111 1111 1111 1111 1110

Теперь, когда он хочет добавить 5, АЛУ получает 2 числа и добавляет их, простое сложение.

Когда ALU получает команду на вычитание, ему дается 2 числа - оно делает НЕ для каждого бита второго числа, выполняет простое сложение и добавляет еще 1 (поскольку дополнение 2 НЕ к каждому биту +1).

Главное здесь помнить, что дополнение 2 было выбрано именно для того, чтобы не делать 2 отдельные процедуры для 2+3 и для 2+(-3).

person Daniel Shaulov    schedule 26.04.2011

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

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

Таким образом, ALU в основном выполняет A + (-B) вместо A - B, но ему не нужен отдельный шаг отрицания. Дизайнеры используют хитрый прием, чтобы сумматоры выполняли и add, и sub за одинаковую длину цикла, добавляя только мультиплексор и вентиль НЕ вместе с новым входом Binvert, чтобы условно инвертировать второй вход. Вот простой пример ALU, который может выполнять AND/OR/ADD/SUB

Полный сумматор

Архитектура компьютера — полный сумматор

Настоящий сумматор — это просто прямоугольник со знаком плюс внутри ⊞, который складывает a с b или ~b и переносит в. em>, производя сумму и выполнение. Это работает, понимая, что в дополнении до двух -b = ~b + 1, поэтому a - b = a + ~b + 1. Это означает, что нам просто нужно установить перенос равным 1 (или отменить перенос для заимствования) и инвертировать второй ввод (т.е. b). Этот тип ALU можно найти в различных книгах по компьютерной архитектуре, таких как

RISC-V АЛУ

В одном дополнении -b = ~b, поэтому вы не устанавливаете перенос, когда хотите вычесть, иначе дизайн будет таким же. Однако у дополнения two есть еще одно преимущество: операции над знаковыми и беззнаковыми значениями также работают одинаково, поэтому вам даже не нужно различать подписанные и беззнаковые типы. В качестве дополнения вам нужно добавить бит переноса обратно к младшему значащему биту если тип подписан

С некоторой простой модификацией вышеупомянутого ALU они теперь могут выполнять 6 различных операций: ADD, SUB, SLT, AND, OR, NOR.

6-function ALU

CSE 675.02: Введение в архитектуру компьютера

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

person phuclv    schedule 23.05.2019

В нотации с дополнением до 2: not B = -B -1 или -B = (not B) + 1. Его можно проверить на компьютере или на бумаге.

Итак, A - B = A + (не B) + 1, что можно выполнить с помощью:

  • 1 побитовое нет
  • 1 шаг
  • 1 дополнение

Есть хитрость, позволяющая неэффективно увеличивать и уменьшать число, используя только отрицания и отрицания.

Например, если вы начинаете с числа 0 в регистре и выполняете:

не, отрицательный, не, отрицательный, не, отрицательный, ... регистр будет иметь значения:

-1, 1, -2, 2, -3, 3, ...

Или как еще 2 формулы:

not(-A) = A - 1
-(not A) = A + 1
person RobertB.    schedule 17.03.2017