[英]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.