为什么有些算术指令有 signed/unsigned 变体而有些没有
Why do some arithmetic instructions have a signed/unsigned variant and some don't
假设我们有:
a = 0b11111001;
b = 0b11110011;
如果我们用手在纸上做 Addition
和 Multiplication
我们会得到这个结果,我们不关心它是否签名:
a + b = 111101100
a * b = 1110110001011011
我知道乘法会使宽度加倍,而加法可能会溢出:
Why do some CPUs have different instructions to do signed and unsigned operations?
我的问题是,为什么像 Add
这样的指令通常没有 signed/unsigned 版本,但 Multiply
和 Divide
有?
为什么我们不能有一个通用的 unsigned multiply
,像我上面做的那样计算并截断结果,如果它被烧焦,与 Add
相同。
或者另一个,为什么 Add
不能有 signed/unsigned 版本。我检查了一些架构,似乎是这样。
我认为您选择的示例误导了您认为可以通过将 8x8 => 16 位无符号产品截断为 8 位来获得带符号的产品。事实并非如此。
(249-256) * (243-256)
= 0x005b
,一个小的正结果,恰好适合整个结果的低半部分。但是完整的带符号结果是 而不是 总是无符号乘积的操作数大小截断。
例如-128 * 127
是-16256
,或者作为16位2的补码,0xc080
.
但是0x80 * 0x7f
是+16256,即0x3f80
。相同的下半部分,不同的上半部分。
或者另一个例子,参见Why are signed and unsigned multiplication different instructions on x86(-64)?
加宽有符号乘法不涉及任何截断。有符号和无符号乘法的低半部分是相同的,这就是为什么 x86 例如只有立即数和 2 操作数形式的 imul
, not also mul
. Only widening multiply needs a separate form. (Or if you want - 所以如果你想你不能轻易使用非加宽 imul
检测完整的未签名结果何时不适合。)
假设我们有:
a = 0b11111001;
b = 0b11110011;
如果我们用手在纸上做 Addition
和 Multiplication
我们会得到这个结果,我们不关心它是否签名:
a + b = 111101100
a * b = 1110110001011011
我知道乘法会使宽度加倍,而加法可能会溢出:
Why do some CPUs have different instructions to do signed and unsigned operations?
我的问题是,为什么像 Add
这样的指令通常没有 signed/unsigned 版本,但 Multiply
和 Divide
有?
为什么我们不能有一个通用的 unsigned multiply
,像我上面做的那样计算并截断结果,如果它被烧焦,与 Add
相同。
或者另一个,为什么 Add
不能有 signed/unsigned 版本。我检查了一些架构,似乎是这样。
我认为您选择的示例误导了您认为可以通过将 8x8 => 16 位无符号产品截断为 8 位来获得带符号的产品。事实并非如此。
(249-256) * (243-256)
= 0x005b
,一个小的正结果,恰好适合整个结果的低半部分。但是完整的带符号结果是 而不是 总是无符号乘积的操作数大小截断。
例如-128 * 127
是-16256
,或者作为16位2的补码,0xc080
.
但是0x80 * 0x7f
是+16256,即0x3f80
。相同的下半部分,不同的上半部分。
或者另一个例子,参见Why are signed and unsigned multiplication different instructions on x86(-64)?
加宽有符号乘法不涉及任何截断。有符号和无符号乘法的低半部分是相同的,这就是为什么 x86 例如只有立即数和 2 操作数形式的 imul
, not also mul
. Only widening multiply needs a separate form. (Or if you want imul
检测完整的未签名结果何时不适合。)