19

我对 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 (顾名思义)?
4

5 回答 5

20

指令名称具有误导性。addu如果您不想在溢出时出现陷阱,请用于有符号和无符号操作数。

add如果出于某种原因需要溢出陷阱时使用。大多数语言不希望有符号溢出的陷阱,因此add很少有用。

于 2013-05-21T00:27:59.567 回答
7

如果您使用带符号的数字,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...
于 2013-05-20T16:59:03.763 回答
4

OVERFLOW不是问题中声明的,这个进位位不是溢出位,在给定的例子中没有溢出,溢出是什么时候:

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

所以坚持add它会标记溢出,并且你的例子中的进位位(这不是溢出)不会打扰你。addu做同样的事情,除非没有引发异常。

于 2014-03-11T15:03:05.957 回答
4

基本上这两个操作码都是签名添加。所以 MIPS 使用 31 位来存储数据,最大数量是 (2 raise to 31)-1,并且保留 1 位来存储数字的符号。如上所述,“add”和“addu”的基本区别在于前者在结果数大于31位可以占用的最大数时抛出异常。后者执行时没有显示任何警告。

例如,3 位加法最大值 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

这就对了。

于 2018-04-28T17:11:03.583 回答
0

在您的示例中,这实际上不是溢出。当符号位的进位不等于符号位的进位时会发生溢出。在您的示例中,虽然符号位的进位是“1”(看似溢出),但符号位的进位也是“1”。因此,在这种情况下,MIPS 不会将其视为溢出。溢出如何发生的模式实际上与结果是否正确相对应。也就是说,如果结果超出了您的位可以表示的范围,则会发生溢出。例如,如果将两个 4 位数 0111 (7) 和 0010 (2) 相加,则会出现溢出,因为结果 (9) 超出了 4 位数可以表示的范围(-8 到 7) . 如果你看一下算术:

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

可以看到,虽然符号位没有进位,但结果仍然不正确。因此这是一个溢出(MIPS 会检测到它)。

于 2018-02-28T20:49:41.357 回答