как определить, включен / выключен флаг переполнения для двоичного сложения со смешанными знаками?

Я до сих пор не совсем понимаю флаги переполнения, но из того, что я собрал, если два наиболее значимых бита положительны и приводят к отрицательному результату, и наоборот, флаг переполнения включается. Но как быть в случае двоичного кода со смешанными знаками? Моя текущая проблема - 70 - -65, что в двоичном формате будет

        0100 0110 
 -1011 1111
  1000 0111

и я предполагаю, что в этом случае флаг переполнения будет включен, потому что 135 находится за пределами диапазона от -128 до 127. Правильно ли это, и есть ли лучший способ определить, включен / выключен флаг переполнения?

3 ответа

Итак, мы знаем, что a - b = a + (-b) и что с дополнением до двух -b = ~b + 1, поэтому a - b = a + ~b + 1. И это то, что процессор будет делать в логике.

               1  <--- here is the plus one
  01000110 
+ 01000000  <--- ~b
==========

заполните это

       010000001
  01000110 
+ 01000000
==========
  10000111

Верхняя строка - это перенос / ввод для каждого бита, а ноль, свисающий слева, - это перенос из 8-битного вычитания / сложения. Обратите внимание, что некоторые процессоры инвертируют это во флаг переноса, называя это заимствованием (если исходная операция была вычитанием), другие просто копируют его во флаг переноса, и вы должны знать, что это не заимствование.

Здесь мы видим две вещи, два способа обнаружения подписанного переполнения (флаг переноса - это беззнаковое переполнение). Самый простой способ увидеть подписанное переполнение - это если выполнение и перенос msbit не совпадают, в этом случае перенос равен 0, а перенос равен 1, они не совпадают, это подписанное переполнение, если эти биты считаются вами, программистом (логика не считает их подписанными или неподписанными, красота дополнения двоек), как подписанные, тогда этот результат не умещается в 8 битах, поэтому результат неверен.

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

      abi cr
000 00 
001 01 <---
010 01
011 10
100 01 
101 10
110 10 <--
111 11 

a и b - операнды, i - перенос, c - перенос, r - результат. Два случая, когда i и c не равны, - это переполнение со знаком. И если вы посмотрите, это правило применяется, если a = b и r! = B, тогда подписанное переполнение.

Это два способа узнать, но вы должны инвертировать b, а не два, а дополнять их. Часто переменные не имеют возможности иметь дополнительный бит. Вы хотели бы использовать 16-битную переменную на языке высокого уровня для выполнения этой 8-битной математики, и вам нужно будет сделать это дважды, один раз с 7 битами и один раз с 8 битами, чтобы увидеть перенос и выполнение. Или вы используете if a = b и r! = B для msbit и вам не нужно делать столько же работы, кроме как выполнять математические вычисления с вычитанием, а затем использовать этот результат как операнд a как есть, и те, которые дополняют msbit b. Ну неужели работы меньше? Придется написать, чтобы увидеть.

И безопаснее говорить / думать о «переполнении со знаком», а не просто говорить / думать «о переполнении», поскольку эта форма переполнения связана со сложением и вычитанием чисел со знаком с использованием дополнения двоек для представления отрицательных чисел. Понимая, что флаг выполнения / переноса является «переполнением без знака» для этих операций. И не путать с переполнением умножения, если вы найдете логику, которая делает это (и использует тот же флаг), которая будет похожа на 0x40 * 0x40 = 0x1000, но с 8-битным умножителем, который не выводит 16 бит 0x40 * 0x40 = 0x00 и он переполнился. Обратите внимание, что не все процессоры заботятся. Некоторые из них будут поддерживать nbit * nbit = 2*nbit, который может обрабатывать все комбинации, но тогда вам нужно иметь умножение со знаком и умножение без знака, что является другой темой.сложение и вычитание не имеют подписанной и неподписанной версии из-за природы дополнения до двоек.

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

Если вы хотите понять, как ALU может вычислить это из двоичных битов, см. «Флаг CARRY» и «OVERFLOW» в двоичной арифметике для объяснения и рабочих примеров.

Однако в принципе не имеет значения, как это на самом деле реализует аппаратное обеспечение ЦП; он просто работает так, как мы хотим, устанавливая флаг переполнения каждый раз, когда точный математический результат выходит за пределы диапазона значений этой ширины целого числа. В противном случае он очищается, и подписанный результат не переносится. например 120 + 10 будет подписано переполнение, если выполнено в 8-битном формате, потому что 130 находится за пределами [-128..127]подписанный 8-битный дополнительный диапазон значений до 2. Так будет -128 + (-10) или -128 - 10.
Но нет -128 - (-10) = -118

Говоря простыми словами, флаг переполнения включается только в двух случаях:1. Если сумма двух чисел со знаком «выкл» (0) дает результат, число с битом знака «включено» (1).2. Если сумма двух чисел со знаком «вкл» (1) дает результат, число с битом знака «выкл.» (0).

Другие вопросы по тегам