[英]Should I use “mul” or “imul” when multiplying a signed number to an unsigned number?
我发现mul
和imul
都可用于将有符号数乘以无符号数。
例如:
global _start
section .data
byteVariable DB -5
section .text
_start:
mov al, 2
imul BYTE [byteVariable]
您可以用mul
替换imul
,结果仍然相同( -10
)。
将有符号数乘以无符号数时mul
和imul
是否完全相同,或者它们之间有区别吗?
如评论中所述,上半部分不同。 如果您不关心上半部分,则可以使用mul
或imul
的所有形式(单操作数形式产生上半部分,但在这种情况下,您将忽略它)。
如果您确实关心上半部分,则mul
和imul
本身都imul
,因为它们只是将 unsigned*unsigned 和 signed*signed 相乘,但您可以很容易地修复它。
考虑有符号字节的位权重为 -128, 64, 32, 16, 8, 4, 2, 1 而无符号字节的位权重为+ 128, 64, 32, 16, 8, 4, 2 , 1. 所以你可以用有符号格式表示x
的无符号值(我知道这很令人困惑,但这是我能做的最好的)作为x + 256 x_7
(其中x_7
是x
7 位)。 最简单的查看方法可能是拆分它: x + 2 * 128 * x_7
。 这里发生的事情是补偿-128 权重,首先通过将第 7 位的值相加 128 次来删除它,然后通过再次执行一直到 +128 权重,当然这可以一步完成。
无论如何,乘以由一些符号数y
和工作出来给出256 x_7 y + xy
,其中xy
是(双宽度)的结果imul
和256 x_7 y
手段“添加y
到上半如果的符号x
是设置”,因此可能的实现是(未测试)
; al has some unsigned value
mov dl, al
sar dl, 7
and dl, [signedByte]
imul BYTE [signedByte]
add ah, dl
自然地,您可以对一个操作数进行符号扩展,对另一个操作数进行零扩展,并使用 16 位乘法(任意,因为上半部分与这种方式无关)。
标志的另一种行为。 对于 MUL:当进位改变上半部分时 OF=CF=1; 对于 IMUL:OF=CF=1 当进位改变低部分的符号位时(或仅在 2 或 3 个操作数形式的结果中改变符号位)
x86确实有一条将有符号字节乘以无符号字节的指令: SSSE3 pmaddubsw
。
您可以将其视为将一个操作数符号扩展到 16 位,将另一个操作数零扩展到 16 位,然后进行 NxN -> N 位乘法。 (对于每个 SIMD 元素)。
它还从相邻字节水平添加成对的单词产品,但如果您用零( punpcklbw
或pmovzxbw
)解压缩输入,那么您可以分别获得每个产品。
当然,如果您有 SSE4.1,那么您可以只pmovsxbw
一个输入和pmovzxbw
另一个输入来提供常规的 16 位pmullw
,如果您不想添加对。
但是,如果您只想要一个标量结果, movsx
/ movzx
来提供常规的非扩展imul reg, reg
是您最好的选择。
正如 Harold 指出的那样, mul r/m
和imul r/m
加宽乘法以相同的方式处理它们的输入,因此它们都不能工作(除非已知有符号输入是非负的,或者已知无符号输入没有其高位设置,所以你可以把它们都一样对待。)
mul 和 imul 还以不同方式设置 FLAGS:CF=OF= 完整结果是否适合下半部分。 (即完整结果是低半部分的零扩展或符号扩展)。 对于imul reg,r/m
或imul reg, r/m, imm
,“低半部分”是目标 reg; 上半部分没有写在任何地方。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.