编辑:我正在使用this计算器检查结果,但似乎计算器本身在计算错误的值,导致了这个问题。
[使用mul
指令时,我注意到将2个高数字相乘会导致错误的值。示例:
mov eax, 0ffffffffh
mov ebx, 0ffffffffh
mul ebx
; eax:00000001 I expected eax to be 0
; edx:FFFFFFFE
mov eax, 0ffffff00h
mov ebx, 0ffffffffh
mul ebx
; eax:00000100 I expected eax also to be 0
; edx:FFFFFEFF
我知道-1 * -1
为1
,ffffffffh
为负1。但是,将这两个数字以无符号乘法相乘不会得到1
,还是这样?其他示例也是如此。
同样在使用imul
指令时,我也会得到奇数,但我认为这是因为有符号乘法:
mov eax, 0fffffff0h
mov ebx, 5
imul ebx
; eax:FFFFFFB0
; edx:FFFFFFFF ; I expected edx to be 4
您的结果正常,您的期望是错误的。 IDK产生了您的错误期望,但32位mul
的64位结果出现在EDX:EAX中。
[来自在线计算器,大概使用了Javascript编号,即带有53位尾数的mul
精度浮点,它将double
舍入到最接近的可表示双精度值,即0xfffffffe00000001
。
对于带符号的情况,您使用的计算器完全错误,希望它将您的输入解释为32位2的补码。
乘法结果的下半部分与您是否将输入解释为有符号无关,因此,作为快捷方式,我们可以使用0xfffffffe00000000
在此处获得下半部分。 (这就是为什么英特尔只费心为-1 * -1 = 1
(例如imul
)添加有效的非扩展表格)。
[如果简单地在像imul eax, edx, -1
这样的扩展精度计算器中试用(在Ubuntu中打包为calc
,在Arch中打包为calc
):
apcalc
因此,这确认了CPU的结果。请记住,和奇数乘以一个奇数就是一个奇数,因此也可以以这种方式排除对calc
的EAX = 0猜测。
对于带符号,使用任意精度计算器有点棘手:
; base2(16) // ask for hex output as well as decimal ; 0x0ffffffff ^ 2 18446744065119617025 /* 0xfffffffe00000001 */ ; 0x0ffffff00 * 0x0ffffffff 18446742969902956800 /* 0xfffffeff00000100 */
那个小的无符号数当然分成
0xffffffff * 0xffffffff
和; (0xfffffff0 - 2^32) * 5 -80 /* -0x50 */ ; . + 2^64 // get the 64-bit 2's complement bit-pattern for that negative number 18446744073709551536 /* 0xffffffffffffffb0 */
,而EDX只是全数,与EAX的高位相同,因为这是符号扩展的工作方式。