Reputation: 3155
I'm using MUL in assembly (MASM) to multiply two integers.
According to the MASM Instruction Set docs, the product is stored in EDX:EAX, the combination of the EDX and EAX registers (if I understand correctly).
So I try printing out the result of the EDX register first then the EAX register to print out the whole number.
But when I get a product that supposedly exceeds the 32bits (10 decimal places), I am getting a strange answer.
For example 100000 * 100000 = 21410065408
, which is wrong.
But for small multiplications, it works.
Here is the assembly code:
; 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
All variables are declared as 32 bit DWORDS
Am I approaching this wrong?
Upvotes: 3
Views: 2812
Reputation: 3119
This is what I use. It is NOT optimal! Nasm syntax, may need minor alteration for Masm. Tweak it up to suit your needs.
; ---------------------------------------- ; 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 ;-------------------------------------
Upvotes: 1
Reputation: 2642
You are doing this arithmetic: 100,000 * 100,000.
We all hope the answer is 10,000,000,000 (Ten billion)
Now, it so happens that ten billion, in hex is,
2 540B E400
My guess (totally guessing here) is that your WriteString
and WriteDec
routines aren't really aware that you may have a large (64 bit) number you are trying to print
This may help clarify a few things...
Ten billions is 2 540B E400
The bottom 32 bits of that are: 540B E400
That value, in decimal, is: 1,410,065,408
That value, if you prepend the digit 2
, is your wrong answer, i.e., 21,410,065,408
Here is a suggested test
Use your existing code to multiply these two numbers...
286,331,153
* 15
and you should get 4,294,967,295
which is one less than 4 Gig
Now increase the first number by 1, and do the multiplication again; i.e.,
286,331,153
* 15
and you should get 4,294,967,310
(i.e., 15 more than the first time).
If your program shows that the answer is 115, you have nailed your bug.
Here's what's going on.
286,331,153
* 15
is also 1111,1111h
* 0000,000Fh
(the commas are for clarity in reading only)
The product is FFFF,FFFFH
or the four gig (minus one) number just mentioned
Now then, it so happens that if we up the number by one, like this
286,331,154
* 15
We now have
1111,1112h
* 0000,000Fh
With the result of: 1 0000 000E
So, if your expected decimal number of 4,294,967,310 actually shows up as 115, you have found your bug.
Upvotes: 1
Reputation: 5884
I believe you are using the Irvine library? That cannot print out 64bit numbers, at least I don't remember it being able to.
So, unless you want to write out your own 64bit number printing routine, just use the c function printf
, masm32 calls it crt_printf
.
You can either create a qword variable to store edx:eax, or you can use a structure.
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
Upvotes: 4