будет ли законным выполнение арифметической операции с парой чисел со знаком и без знака? - PullRequest
4 голосов
/ 10 января 2011

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

10000001 (1-байтовое целое и считается беззнаковым, эквивалентным 129)
+
11111111 (1-байтовое целое и считается подписанным (двухкомпонентная система), эквивалентно -1)


10000000 (1-байтовое целое и в беззнаковой логике, эквивалентной 128)

Теперь, если верхнее значение было в регистре AL и у нас был следующий код инструкции (в формате GAS):

addb -1, %al

, тогда флаг переноса (CF) регистра EFLAGS будет установлен после выполнения операции и сообщит о превышенииlow, чего на самом деле не произошло, и, возможно, из-за одного числа без знака в терминах переполнения следует ссылаться на флаг переполнения (OF) регистра EFLAGS.Поэтому я запутался, если делать что-либо разумно.

Ответы [ 5 ]

6 голосов
/ 10 января 2011

Математически вы не добавляете число со знаком или без знака.Есть только значения по модулю 2 32 (при условии, что у вас есть 32-битные регистры).Такие значения охватывают диапазон 2 32 последовательных целых чисел, но вы можете интерпретировать этот диапазон как начинающийся где угодно.«Signed» и «unsigned» - это всего лишь две такие интерпретации.

Другими словами, в 4-битных регистрах интерпретация без знака «1011» равна одиннадцати, в то время как интерпретация со знаком - минус пять.Но есть только одно значение (которое математики обычно называют «одиннадцать по модулю 2 4 », потому что математики традиционно любят неподписанную интерпретацию).Например, если вы добавите «0110» к этому значению (которое равно «шести» в интерпретации со знаком и без знака), то вы получите «0001», что является правильным значением: минус пять плюс шесть дают один, а одиннадцать плюсшесть - это семнадцать, что также равно единице при уменьшении по модулю 2 4 (семнадцать означает один плюс шестнадцать; "уменьшение по модулю 2 4 " означает деление на шестнадцать [это 2 4 ] и сохраняя только остаток).

Другой способ сказать следующее: количество (двоичных) цифр для числового значения концептуально бесконечно слева.Регистр ЦП хранит только 32 самых правых бита.Интерпретация без знака заключается в предположении, что все самые левые биты равны нулю.Интерпретация со знаком подразумевает, что обычно все самые левые биты имеют одинаковое значение, чем бит 31 (т.е. все равны нулю или все равны единице).В любом случае, когда вы выполняете сложение (или вычитание или умножение), переносы распространяются справа налево, а не наоборот, поэтому значения этих игнорируемых битов не имеют никакого отношения к 32-битному результату.Таким образом, существует только один опкод «add», который не заботится о том, являются ли его операнды в мозгу программиста «подписанными» или «беззнаковыми».

Подпись должна приниматься во вниманиепри выполнении операции, которая не совместима с арифметикой по модулю.Преобразование в последовательность десятичных цифр для отображения является такой операцией.Однако более частым случаем являются сравнения.Значения по модулю 2 32 не упорядочены;они находятся в некотором циклическом цикле (когда вы добавляете 1 к 2 32 -1 и уменьшаете по модулю 2 32 , вы возвращаетесь к 0).Сравнения имеют смысл только тогда, когда вы рассматриваете целых чисел во всем диапазоне целых чисел.На этом этапе вы должны решить, используете ли вы подписанную или неподписанную интерпретацию.Вот почему процессоры x86 предлагают и jg (переход, если больше, интерпретация со знаком) и ja (переход, если выше, интерпретация без знака).

3 голосов
/ 10 января 2011

На двоичном уровне есть только одна операция сложения:

 0101 + (5)
 1010 = (unsigned 10 or signed -6)
--------
 1111   (unsigned 15 or signed -1)

Что касается флагов переноса и переполнения, они оба установлены в соответствии с простыми правилами.CF может использоваться для обнаружения переполнения если , мы считаем, что операнды были беззнаковыми, а OF для обнаружения переполнения если мы считаем, что они оба подписаны.Оба эти флага установлены в соответствии с результатом, и вам решать, какой из них использовать.

Фактическая формула для флага OF:

OF = CF xor MSB_of_result.

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

3 голосов
/ 10 января 2011

Является ли число или операция подписанной или неподписанной, это просто вопрос интерпретации. Что произойдет, когда вы сделаете добавление, это то, что эти два числа будут сложены вместе, чтобы сделать 10000000 с 1 в флаге переноса (потому что он «вышел из внешнего интерфейса»). Затем ваши последующие операции должны интерпретировать, что это значит (если вы используете бит в другом месте, это как если бы вы рассматривали операцию как добавление без знака без переноса; если вы отбрасываете бит, это как если бы вы делали подписанный бит добавить).

1 голос
/ 15 января 2011

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

1 голос
/ 10 января 2011

«Подпись» и «без знака» являются интерпретациями.Инструкция по сборке, как правило, должна иметь документальное подтверждение.Мне неизвестна какая-либо архитектура, в которой есть инструкция ADD-SIGNED-UNSIGNED, которая интерпретирует один из своих аргументов как значение со знаком, а другой как как беззнаковое.Кажется, в этом тоже есть небольшая ценность.В случае целочисленной арифметики с дополнением 2s единственное различие заключается в некоторых флагах-регистрах.

...