写mips代码进行双重操作 精度整数减法 64位数据。假设第一个操作数 在寄存器$ t4(hi)和 $ t5(lo),$ t6(hi)和 $ T7(LO)。
我对答案的解决方案是
sub $t3, $t5, $t7 # Subtract lo parts of operands. t3 = t5 - t7
sltu $t2, $t5, $t7 # If the lo part of the 1st operand is less than the 2nd,
# it means a borrow must be made from the hi part
add $t6, $t6, $t2 # Simulate the borrow of the msb-of-low from lsb-of-high
sub $t2, $t4, $t6 # Subtract the hi's. t2 = t4 - t6
然而,作者给出了解决此问题的方法如下
对于有符号的双精度整数,
subu $t3, $t5, $t7
sltu $t2, $t5, $t7
add $t6, $t6, $t2
sub $t2, $t4, $t6
对于无符号双精度整数,
subu $t3, $t5, $t7
sltu $t2, $t5, $t7
addu $t6, $t6, $t2
subu $t2, $t4, $t6
我对sub/add
和subu/addu
操作差异的理解是溢出异常是在sub/add
中生成的,而不是在subu/addu
中生成的。 sub/add
和subu/addu
都减去/添加操作数的位,对有符号或无符号的操作数的解释与slt
和sltu
指令不同,对结果没有影响
问题1
我从作者推断出解决方案正在处理溢出检测,而我在解决方案中没有想到相同的问题。我对吗?还有其他我想念的东西吗?
问题2
假设我的上述推论是正确的,为什么在使用addu
和subu
减去无符号双精度的情况下,作者提供的解决方案会关闭溢出检测?
答案 0 :(得分:6)
对于加法和减法,除了溢出的概念之外,有符号和无符号操作数之间没有区别。当结果的数值与您获得的位序列的解释不匹配时,会发生溢出。
例如,考虑8位序列(MIPS具有32位寄存器,但对于我的示例,8位更容易)。让我们假设无符号解释:8位序列表示0到255(含)之间的数值。如果我将10010011(数值147)添加到01110110(数值118),那么我得到00001001(数值9)。 9不等于147 + 118。我得到那个结果,因为数学值是265,不能适合8位。加法结果需要9位,但上面的第9位已被删除。
现在,想象一下使用签名解释的相同示例。 10010011现在的数值为-109。 01110110仍然具有数值118,并且获得的结果(00001001)具有值9. -109和118的数学和为9,因此没有溢出。
这意味着溢出的概念取决于您如何解释这些值。有符号和无符号解释的加法机制是相同的(对于相同的输入比特序列,你得到相同的输出比特序列 - 这是对负有符号值使用二进制补码的全部要点)但溢出处理不同。 / p>
MIPS架构提供了在溢出时触发异常的方法。从概念上讲,对32位字有三个可能的加法运算:
MIPS实现了前两种添加,分别带有addu
和add
操作码。在MIPS文档中,它们分别被称为 unsigned 和 signed arithmetics 。没有用于在无符号溢出上引发异常的操作码。在实践中,C编译器仅使用addu
,但是他们可以使用add
作为签名类型(这是C标准允许的,但会破坏大量现有代码)。 Ada编译器使用add
,因为Ada强制执行溢出检查。
有人说......
Patterson和Hennessey希望在64位整数上实现有符号和无符号算术。对于未签名的算术,他们不希望任何例外,因此他们使用addu
和subu
。对于已签名的算术,当数学结果不适合具有带符号解释的 64位序列时,他们希望发生异常。它们不希望引发异常,因为在处理低32位的一半时会出现一些类似寄生溢出的情况。这就是他们为低部分使用subu
的原因。
您的解决方案是错误的,因为它可能引发异常,而不应该这样做。假设您要从-2000000000减去2000000000(二十亿)(减去二十亿)。数学结果是40亿(四十亿)。两个操作数和结果肯定适合64位(可表示的范围是-9223372036854775808到9223372036854775807)。因此,对于64位带符号的算术,没有溢出:应该没有异常。但是,在这种情况下,您的第一个sub
会报告溢出。 sub
适用于32位值并签名 32位算术。它的操作数将是01110111001101011001010000000000和10001000110010100110110000000000。请注意,这些值都适合32位:这些值的32位带符号解释分别为正负两十亿。然而,减法结果是四十亿,并且它不适合32位(作为有符号数)。因此,您的sub
会引发异常。
根据经验,溢出检测是指依赖于符号解释的操作,这会影响对最重要位的处理。对于大整数算术,除了最重要的词之外的所有词都应被视为无符号,因此到处都是addu
/ subu
。作为第一步,如果你首先专注于未签名的算术,事情会更容易理解,毫无例外(那么你只需使用addu
和subu
,而永远不会 {{1 }或add
)。