Как CPU делает вычитание
У меня есть некоторые основные сомнения, но каждый раз, когда я сижу, чтобы попробовать свои силы в вопросах интервью, эти вопросы и мои сомнения всплывают.
Скажи A=5
B=-2
Я говорю A+B. Я предполагаю, что A и B являются 4-байтами Как CPU делает это дополнение? Я понимаю, что A будет иметь знаковый бит (MSB) как 0 для обозначения положительного целого числа и B будет иметь знак бит как 1 для обозначения отрицательного целого числа.
теперь, когда в программе c++ я хочу напечатать A+B, делает модуль сложения ALU (арифметический логический блок) сначала проверяет знаковый бит, а затем решает сделать вычитание, а затем следовать процедуре вычитания. Как производится вычитание, будет моим следующим вопросом.
A=5
B=2
хотите сделать A-B компьютер возьмет 2 секунды дополнения B и добавит дополнение A+2s и вернет это (после отбрасывания дополнительного бита слева)?
A=2
B=5
сделать A-B Как работает компьютер в этом кейс?
Я понимаю, что любой if-then и т. д. вид условной логики все будет сделано в аппаратном обеспечении внутри ALU. вычисление 2S дополняет и т. д., отбрасывая дополнительный бит, все будет сделано в аппаратном обеспечении внутри ALU. Как выглядит этот компонент ALU?
спасибо,
4 ответов
вся причина, по которой мы используем 2 дополнения является ли это сложение одинаковым, являются ли числа положительными или отрицательными - нет особых случаев для рассмотрения, как есть с 1 дополнения или подпись-величина представлений.
найти A-B
, мы можем просто отрицать B и добавлять; то есть мы находим A + (-B)
, и поскольку мы используем дополнение 2, мы не беспокоимся, если (-B)
положительно или отрицательно, потому что дополнение-алгоритм работает одинаково в любом случае.
вы немного ошибаетесь в битной части знака. Это не просто знаковый бит - каждое отрицательное число преобразуется в 2 дополнения. Если вы пишете:
B = -2
Компилятор при компиляции его в двоичный файл сделает это:
1111 1111 1111 1111 1111 1111 1111 1110
Теперь, когда он хочет добавить 5, ALU получает 2 числа и добавляет их, простое добавление.
Когда ALU получает команду на вычитание, ему дается 2 числа - это делает не каждый бит второго числа и делает простой добавление и добавляет еще 1 (потому что дополнение 2 не к каждому биту +1).
основная вещь здесь, чтобы помнить, что дополнение 2 было выбрано именно с целью не делать 2 отдельные процедуры для 2+3 и для 2+(-3).
подумайте в терминах двух или трех битов, а затем поймите, что эти вещи масштабируются до 32 или 64 или howevermany бит.
во-первых, давайте начнем с decimal
99
+22
===
для того, чтобы сделать это, мы будем иметь некоторые "нести один" происходит.
11
99
+22
===
121
9 плюс 2 1 носит одно, 1 плюс 9 плюс 2 2 носит одно...
дело в том, чтобы заметить, что для добавления двух чисел мне действительно нужны три строки, по крайней мере, для некоторых из них я возможно, нужно уметь складывать три числа. То же самое с сумматором в alu, каждый столбец или битовая полоса, однобитовый сумматор, должен иметь возможность добавлять два входа плюс бит переноса, а выход-один бит результата и один бит переноса.
поскольку вы использовали 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
и что вы знаете, мы получаем тот же ответ...не имеет значения, что на самом деле значения для любого из операндов. если это операция добавления, вы ставите ноль на бит переноса и подаете его в сумматор. Если это операция вычитания, вы инвертируете второй операнд и кладете один на перенос и подаете его в тот же сумматор. Все, что выпадает, выпадает. Если у вашей логики достаточно битов, чтобы удержать результат, тогда все работает, если у вас недостаточно места, вы переполняетесь.
существует два вида переполнения, без знака и подписи. Unsigned просто это бит переноса. Подписанное переполнение связано с сравнением бита переноса в столбце 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 установлен.
если / когда у вас есть add с инструкцией по переносу, они берут ту же схему сумматора, и вместо подачи переноса в нуль подается флаг переноса. Аналогично вычитание с заимствованием, вместо подачи переноса в 1 перенос либо 1 или 0 в зависимости от состояния флага переноса в регистре статуса.
умножение-это совсем другая история, двоичный делает умножение намного проще, чем когда сделано с десятичной математикой, но у вас должны быть разные инструкции по умножению без знака и подписи. И разделение - это свой собственный отдельный зверь, поэтому большинство наборов инструкций не имеют разделения. Многие не имеют умножения из-за количества ворот или часов, которые он сжигает.
в нотации дополнения 2: Не B = - B -1 или-B = (не B) + 1. Это можно проверить на компьютере или на бумаге.
таким образом, A-B = A + (не B) + 1, который может быть выполнен с:
1 побитовое не
1 шаг
1 дополнение
есть трюк, чтобы неэффективно увеличивать и уменьшать, используя только нет и отрицания. Например, если вы начинаете с числа 0 в регистр и выполнить:
нет, нег, нет, нег, не, отрицательный. ,.. регистр будет иметь значения:
-1, 1, -2, 2, -3, 3, ...
или как еще 2 Формулы:
not (- A) = A-1
- (Не A) = A + 1