我在汇编(MASM)中使用MUL来乘以两个整数。
根据MASM指令集文档,产品存储在EDX:EAX中,EDX和EAX寄存器的组合(如果我理解正确的话)。
所以我首先尝试打印出EDX寄存器的结果,然后打印EAX寄存器以打印出整个数字。
但是当我得到的产品应该超过32位(小数点后10位)时,我得到一个奇怪的答案。
例如100000 * 100000 = 21410065408
,这是错误的。
但是对于小的乘法,它可以工作。
这是汇编代码:
; MULTIPLY
mov eax, var1 ; var1 and var2 from user input
mul var2
mov productResultEDX, edx
mov productResultEAX, eax
; PRINT RESULT
; mov edx, OFFSET productMsg
call WriteString
mov eax, productResultEDX
call WriteDec ; prints out EAX register data
;mov eax, productResultEAX
;call WriteDec
所有变量都声明为32位DWORDS
我接近这个错误吗?
答案 0 :(得分:3)
我相信你使用的是Irvine图书馆?这不能打印64位数字,至少我不记得它能够。
因此,除非您想要编写自己的64位数字打印例程,否则只需使用c函数printf
,masm32将其称为crt_printf
。
您可以创建qword变量来存储edx:eax,也可以使用结构。
include masm32rt.inc
include msvcrt.inc
includelib msvcrt.lib
BigNum struc
LoWord dd ?
HiWord dd ?
BigNum ends
.data
fmtqw1 db "100000 * 100000 = %llu",13, 10, 0
fmtqw2 db "400030 * 500020 = %llu",13, 10, 0
.data?
myqword dq ?
BigNumber BigNum <>
.code
start:
mov eax, 100000
mov ecx, 100000
mul ecx
mov dword ptr[myqword], eax
mov dword ptr[myqword + 4], edx
invoke crt_printf, offset fmtqw1, myqword
mov eax, 400030
mov ecx, 500020
mul ecx
mov BigNumber.LoWord, eax
mov BigNumber.HiWord, edx
invoke crt_printf, offset fmtqw2, BigNumber
inkey
invoke ExitProcess, 0
end start
答案 1 :(得分:1)
你正在做这个算术:100,000 * 100,000。
我们都希望答案是10,000,000,000(100亿)
现在,碰巧有十亿,十六进制,
2 540B E400
我的猜测(完全在这里猜测)是你的WriteString
和WriteDec
例程并不是真的意识到你可能有一个大的(64位)数字你正在尝试打印
这可能有助于澄清一些事情......
十亿,2 540B E400
其中最后32位是:540B E400
该值以十进制表示:1,410,065,408
如果您在数字2
前面加上该值,则表示您的错误答案,即21,410,065,408
这是建议的测试
使用现有代码将这两个数字相乘......
286,331,153
* 15
您应该得到4,294,967,295
,其中一个小于4 Gig
现在将第一个数字增加1,再次进行乘法运算;即,
286,331,153
* 15
您应该获得4,294,967,310
(即比第一次增加15个)。
如果您的程序显示答案是115,那么您已经确定了错误。
这是发生了什么。
286,331,153
* 15
也是1111,1111h
* 0000,000Fh
(逗号仅供阅读使用)
产品是FFFF,FFFFH
或刚刚提到的四个演出(减一)
现在,如果我们将数字增加一个,就像这样
286,331,154
* 15
我们现在有
1111,1112h
* 0000,000Fh
结果为:1 0000 000E
因此,如果您的预期十进制数4,294,967,310实际显示为115,则表示您已找到错误。
答案 2 :(得分:1)
这就是我使用的。这不是最佳的! Nasm语法,可能需要对Masm进行微小改动。调整它以满足您的需求。
; ----------------------------------------
; u64toda - converts (64 bit) integer in edx:eax
; to (comma delimited) decimal representation in
; ascii zero terminated string in buffer pointed to by edi
;--------------------------------------------
u64toda:
pusha
mov ebx, edx ; stash high dword
mov esi,0Ah ; prepare to divide by 10
xor ecx, ecx ; zero the digit count
jmp highleft ; check is high word 0 ?
highword:
xchg eax,ebx ; swap high & low words
xor edx,edx ; zero edx for the divide!
div esi ; divide high word by 10
xchg eax,ebx ; swap 'em back
div esi ; divide low word including remainder
push edx ; remainder is our digit - save it
inc ecx ; count digits
highleft:
or ebx,ebx
jnz highword
lowleft:
xor edx,edx ; zero high word
div esi ; divide low word by 10
push edx ; our digit
inc ecx ; count it
or eax,eax ; 0 yet ?
jne lowleft
cmp ecx, byte 4 ; commas needed ?
jl write2buf ; nope
xor edx,edx ; zero high word for divide
mov eax,ecx ; number of digits
mov ebx,3
div ebx
mov esi,edx ; remainder = number digits before comma
test edx,edx
jnz write2buf ; no remainder?
mov esi,3 ; we can write 3 digits, then.
write2buf:
pop eax ; get digit back - in right order
add al,30H ; convert to ascii character
stosb ; write it to our buffer
dec esi ; digits before comma needed
jnz moredigits ; no comma needed yet
cmp ecx,2 ; we at the end?
jl moredigits ; don't need comma
mov al,',' ; write a comma
stosb
mov esi,03h ; we're good for another 3 digits
moredigits:
loop write2buf ; write more digits - cx of 'em
mov al,00h ; terminate buffer with zero
stosb
popa
ret
;-------------------------------------