Разница между адд и адду

Я смущен разницей между add и addu.

Ссылка на инструкцию MIPS гласит:

  • добавить (с переполнением)
  • добавить без знака (без переполнения)

Насколько я понимаю, использовать add с подписанными операндами и addu с неподписанными операндами.

Но давайте рассмотрим этот пример (только с 6 битами):

переполнение
|
В
1 | 1 1 1 <- нести
  | 1 1 1 1 0 1 +
  | 1 1 1 1 1 0 =
-----------------
  | 1 1 1 0 1 1

И это мои рассуждения:

  • если я рассмотрим первый и второй числа со знаком операнда (дополнение к двум), то результат будет правильным (-3 + -2 = -5), и я не хочу исключения переполнения. Поэтому я бы использовал addu, чтобы избежать этого исключения, но, хотя результат тот же, название предлагает использовать addu для чисел без знака!
  • если я рассматриваю первый и второй числа без знака операнда, то я хочу, чтобы было поднято исключение (потому что 61 + 62 не равно 59). Так что я бы использовал add, чтобы вызвать исключение, а не addu, как подсказывает название.

Теперь мои вопросы:

  • предполагая, что операнды являются знаковыми (отрицательными в приведенном выше примере) числами, должен ли я использовать addu (как подсказывают мои рассуждения) или мне следует использовать add (как следует из названия)?
  • Предполагая, что операнды являются беззнаковыми (положительными) числами, должен ли я использовать add (как подсказывает мой аргумент) или addu (как следует из названия)?

5 ответов

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

использование add если вам нужна ловушка при переполнении по какой-то причине. Большинство языков не хотят ловушки при переполнении со знаком, поэтому add редко бывает полезным.

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

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

Вот фрагмент кода, показывающий, как вы будете проверять переполнение в неподписанном добавлении:

    li $a1, 0xFFFF0FFF
    li $a2, 0x00010000

    addu $a3, $a1, $a2  # This unsigned addition overflows (set $a3 to $a1+$a2)
    bgt $a1, $a3, overflowed
    bgt $a1, $a2, overflowed
    # If you get here, unsigned addition did not overflow
  # your code goes here...
overflowed:
    # If you get here, unsigned addition overflowed
  # your code goes here...

В основном оба кода являются подписанным дополнением. Таким образом, в MIPS они используют 31 бит для хранения данных, максимальное число (от 2 до 31)-1, а 1 бит зарезервирован для хранения знака для чисел. Как указано выше, основное различие между "add" и "addu" заключается в том, что первое выдает исключение, когда число результата больше максимального числа, занимаемого 31 битом. Последний выполняется без отображения каких-либо предупреждений.

Например, 3-битное сложение max num = (2**(n-1))-1 minumem num = -(2**(n-1)), поэтому в нашем случае max = 3 и min = -4

li $t1,3
li $t2,1
add $t3,$t1,$t2 -----> throws an arthimetic overflow exception

addu $t3,$t1,$t2 ------> t3 = -4

это оно.

OVERFLOW НЕ соответствует заявленному в вопросе, этот бит переноса НЕ является битом переполнения, в данном примере нет NO OVERFLOW, переполнение происходит, когда:

MSB1 = 1 && MSB2 = 1 && MSBofRESULT = 0
OR
MSB1 = 0 && MSB2 = 0 && MSBofRESULT = 1 

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

Это на самом деле не переполнение в вашем примере. Переполнение происходит, когда перенос в знаковый бит не равен переносу знакового бита. В вашем примере, хотя вынос символа знака равен "1" (казалось бы, переполнение), бит переноса знака также равен "1". Следовательно, в этом состоянии MIPS не будет рассматривать его как переполнение. Паттерн того, как происходит переполнение, фактически соответствует правильности результата. То есть, если результат находится за пределами диапазона, который могут представлять ваши биты, происходит переполнение. Например, если вы добавите два 4-битных числа 0111 (7) и 0010 (2) вместе, вы получите переполнение, так как результат (9) выходит за пределы диапазона, который может представлять 4-битное число (от -8 до 7), Если вы посмотрите на арифметику:

0111 (7) + 0010 (2) = 1001 (-7)

Вы можете видеть, что хотя бит знака не переносится, результат все равно неверен. Поэтому это переполнение (и MIPS обнаружит его).

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