我认为2的补码的整个要点在于可以使用相同的方式对有符号和无符号数字执行操作。 维基百科甚至特别列出乘法是其中受益的操作之一。那么为什么x86需要针对每种类型(mul和imul)分别提供指令?x86-64是否仍然如此?
我认为2的补码的整个要点在于可以使用相同的方式对有符号和无符号数字执行操作。 维基百科甚至特别列出乘法是其中受益的操作之一。那么为什么x86需要针对每种类型(mul和imul)分别提供指令?x86-64是否仍然如此?
加法和减法是相同的,乘法的低半部分也是相同的。但是完整的乘法不同。一个简单例子:
在32位二进制补码中,-1与无符号数2**32 - 1具有相同的表示方式。然而:
-1 * -1 = +1
(2**32 - 1) * (2**32 - 1) = (2**64 - 2**33 + 1)
(请注意,两个结果的低32位是相同的;这就是我所说的“乘法低半部分”相同的含义)。
imul rs, rd1[, rd2]
),而mul只有一种形式(mul rx
)。 - phuclv两个16位数的乘积得到一个32位的结果。 即使其中一个数字是“1”,处理器也会将另一个数字有效地扩展到32位。 将数字扩展到更长的位长度是有符号和无符号值之间不同的操作之一(另一个重要操作是符号比较,这也是除法的重要部分)。
两个和三个操作数版本的结果相同,除了mul和imul指令在设置CF和OF标志(进位和溢出)方面有所不同。
以溢出为例,想象一下-1 * -1与0xFFFFFFFF * 0xFFFFFFFF的情况,你就能理解了。
mul
指令没有 2 或 3 操作数版本。唯一的区别 可能 是 FLAGS 设置,但这种情况很少出现,因此英特尔决定只提供更快的非扩展乘法 imul
操作码。相关:C unsigned long long 和 imulq 取决于这个决定:如果你想要一个溢出检查的无符号乘法,不幸的是你需要使用单操作数 mul
而不是尝试从 imul reg,reg
的 FLAGS 中做些什么。 - Peter Cordes
imul reg,r/m
而不是单操作数扩展形式的不同乘法形式。还有无符号和有符号乘法的最低有效位相同数量是多少? - Peter Cordes