【问题标题】:Difference between add and adduadd 和 addu 的区别
【发布时间】:2013-05-14 02:26:09
【问题描述】:

我对 add 和 addu 之间的区别感到困惑。

MIPS 指令参考说:

  • 添加(有溢出)
  • 添加无符号(无溢出)

我的理解是 add 与带符号的操作数一起使用,而 addu 与无符号的操作数一起使用。

但是让我们考虑这个例子(只有 6 位):

溢出 | 五 1 | 1 1 1

这是我的推理:

  • 如果我考虑第一个和第二个操作数有符号 数字(二进制​​补码),那么结果是正确的(-3 + -2 = -5)并且我不想要溢出异常。所以我会使用 addu 来避免这个异常,但是,虽然结果是一样的,但顾名思义,使用 addu 是为了无符号数!
  • 如果我考虑第一个和第二个操作数 unsigned 数字,那么我希望引发异常(因为 61 + 62 不等于 59)。所以我会使用 add 来引发异常,而不是 addu,正如其名称所暗示的那样。

现在我的问题是:

  • 假设操作数是有符号的(在上面的示例中为负数)数字,我应该使用 addu(正如我的推理所示)还是应该使用 add(顾名思义)?
  • 假设操作数是无符号(正)数,我应该使用 add(正如我的推理所示)还是 addu(顾名思义)?

【问题讨论】:

  • 非常糟糕的指令。不存在未签名添加或签名添加之类的东西。它与陷阱有关,是否应该是 addut 或类似的东西......(仍然可以,因为汇编程序不像机器代码那样刻在石头上)

标签: add mips instruction-set


【解决方案1】:

指令名称具有误导性。对有符号和无符号操作数使用addu,如果您确实想要在溢出时设置陷阱。

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

【讨论】:

    【解决方案2】:

    如果您使用带符号的数字,如果您希望在结果溢出时生成陷阱,则应使用add

    如果您使用无符号数字,则应始终使用addu,并通过将结果与任一数字进行比较来检查加法是否溢出(如果结果小于操作数,则加法是否溢出)。

    这里有一个 sn-p 来显示如何检查无符号加法中的溢出:

        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...
    

    【讨论】:

    • 感谢您的回复!但是...为什么我要在有符号数字上捕获异常?每次结果为负数时都会引发它。其次,你能给我一个在第二种情况下(即无符号数)溢出检查的例子吗?当我可以简单地使用 add 时,为什么还要使用这种溢出检查?
    • @collimarco:不会在每次结果为负数时引发。如果操作结果溢出(即结果数字,在 A2-compliment 中看到的数字不是正确的数字),它将被引发。例如,如果您添加 -3 + -5,则结果将为负 (-8),并且不会引发陷阱。
    【解决方案3】:

    OVERFLOW 是问题中声明的 NOT,此进位位不是溢出位,在给定的示例中没有 OVERFLOW,溢出是在:

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

    所以坚持使用add 它将标记溢出,并且您示例中的进位位(这不是溢出)不会打扰您。 addu 做同样的事情,只是没有引发异常。

    【讨论】:

      【解决方案4】:

      基本上两个操作码都是有符号加法。所以 MIPS 使用 31 位来存储数据,最大数量是(2 提高到 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
      

      就是这样。

      【讨论】:

        【解决方案5】:

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-10-09
          • 2018-05-08
          • 2015-09-06
          相关资源
          最近更新 更多