Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 为什么x86(-64)上的有符号乘法和无符号乘法指令不同?_Assembly_X86_X86 64_Twos Complement - Fatal编程技术网

Assembly 为什么x86(-64)上的有符号乘法和无符号乘法指令不同?

Assembly 为什么x86(-64)上的有符号乘法和无符号乘法指令不同?,assembly,x86,x86-64,twos-complement,Assembly,X86,X86 64,Twos Complement,我认为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位是相同的;这就是我所说的“

我认为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位是相同的;这就是我所说的“乘法的低位半”是相同的意思)。

对于2和3操作数版本,结果是相同的,只是mul和imul指令在设置CF和标志(进位和溢出)的方式上有所不同


想想这两种情况:-1*-1与0xFFFFFF*0xFFFFFF在溢出方面的比较,你就会明白了。

两个16位数字相乘会产生一个32位的结果。即使其中一个数字是“1”,处理器也会有效地将另一个扩展到32位。将数字扩展到更长位长度的过程是有符号值和无符号值不同的操作之一(符号重要的另一个重要操作是幅度比较,这也是除法的一个重要部分)。

对于什么操作数范围,我可以期望mul和imul给出按位相同的结果?当两个操作数都为正且其结果不超过2**63-1时?(也就是说,当无符号结果太小而无法翻转符号位时)@JosephGarvin:不,只要你超出原始长度一位,你就需要单独的指令。考虑例如“代码>1×1=-1”/代码> VS> 0xFFFFFFFF**=0xFFFFFFF</代码>。由于结果的低一半是相同的,并且C程序经常产生与操作数相同大小的结果,所以现代x86 CPU通常具有更多的形式(<代码> IMUL RS,RD1[,RD2] < /代码>)虽然mul只有一种形式
mul rx
,但在有符号和无符号版本中,结果的高半部分是不同的,但它们是不同的,因此可以从高符号结果中获得高无符号结果,反之亦然。该答案的表述不同:有点相关:没有2或3个操作数版本的。唯一的区别是标志设置,但这几乎不需要,英特尔决定只提供更快的非加宽乘法作为操作码。相关:取决于这个决定:如果您想要一个溢出检查的无符号乘法,不幸的是您想要一个操作数
mul
,而不是尝试使用
imul reg,reg
中的标志执行操作。