将有符号数字乘以无符号数时,我应该使用“mul”还是“imul”?

时间:2017-08-03 22:46:31

标签: assembly x86 multiplication unsigned signed

我发现mulimul都可以用来将有符号数乘以无符号数。

例如:

global _start

section .data
    byteVariable DB -5

section .text
_start:

mov al, 2
imul BYTE [byteVariable]

您可以将imul替换为mul,结果仍然相同(-10)。

签名的号码与无符号号码相乘时,mulimul是否完全相同,或者它们之间是否存在差异?

3 个答案:

答案 0 :(得分:3)

正如评论中所提到的,上半部分是不同的。如果你不关心上半部分,你可以使用mulimul的所有形式(单操作数形式产生上半部分,但在这种情况下你会忽略它。)

如果你关心上半部分,那么mulimul都不能正常工作,因为它们只是将unsigned * unsigned和signed * signed相乘,但你可以很容易地修复它。

考虑有符号字节的位权重为-128,64,32,16,8,4,2,1,而无符号字节的位权重 + 128,64 ,32,16,8,4,2,1。所以你可以用签名格式表示x的无符号值(我知道这很令人困惑,但它是我能做的最好的){{{ 1}}(其中x + 256 x_7x_7的第7位)。最简单的方法是分割它:x。这里发生的是补偿-128的重量,首先通过将第7位的值加128次然后再一次将其移至+128重量来移除它,当然这可以做到一步到位。

无论如何,将其与某个已签名的数字x + 2 * 128 * x_7相乘并进行处理会得到y,其中256 x_7 y + xyxy和{{的{双倍宽度]结果如果imul的符号设置为"则表示"将256 x_7 y添加到上半部分,因此可能的实现是(未测试)

y

当然,您可以对一个操作数进行符号扩展,对另一个操作数进行零扩展,并使用16位乘法(任何,因为上半部分与此无关)。

答案 1 :(得分:0)

标志的另一行为。对于MUL:当进位改变上半部分时,OF = CF = 1;对于IMUL:OF = CF = 1,当进位更改低位的符号位(或只是2或3个操作数形式的结果的符号位)

答案 2 :(得分:0)

x86 确实有一条指令,将有符号字节乘以无符号字节:SSSE3 pmaddubsw

您可以将其视为将一个操作数符号扩展为16位,将另一个操作数零扩展为16位,然后执行NxN-> N位乘法。 (对于每个SIMD元素)。

它还会从相邻字节中水平添加单词乘积对,但是如果用零(punpcklbwpmovzxbw)解包输入,则可以分别获得每个乘积。

当然,如果您有SSE4.1,那么如果您不愿意,可以pmovsxbw一个输入,pmovzxbw另一个输入来填充常规的16位pmullw配对。


但是,如果您只想获得一个标量结果,则最好的选择是movsx / movzx,以提供定期的非扩展imul reg, reg

正如Harold指出的那样,mul r/mimul r/m的加倍乘法以相同的方式对待它们的两个输入,因此它们都不起作用(除非已知有符号输入为非负,或者无符号输入为已知没有设置高位,因此您可以对它们进行相同的对待。)

mul和imul对FLAGS的设置也不同:CF = OF =整个结果是否适合下半部分。 (即完整的结果是下半部分的零扩展或符号扩展)。对于imul reg,r/mimul reg, r/m, imm,“下半部分”是目标寄存器;高半部分没有写在任何地方。