News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Division problem

Started by Ani_Skywalker, October 30, 2011, 12:33:57 AM

Previous topic - Next topic

Ani_Skywalker

Hi,

I've got an odd division problem. Everything else works but when the div-instruction is added to the code, it breaks in runtime. If I comment that line out, everything else works fine. I marked the troubling line out with a capital letters.


include \masm32\include\masm32rt.inc ; All includes needed for comon MASM32-programming

primeCheck proto :DWORD ; Function prototypes

.code
start:

call main
inkey ; Wait for input to close console
exit

main proc
local current_nr :DWORD ; Local variables
local primes_found :DWORD

mov current_nr, 3 ; Initialize local variables
mov primes_found, 2

search10001: ; A loop that goes on until the 10001th prime number is found
add current_nr, 2 ; Increase with 2 since only uneaven numbers are primes (besides 2)
push current_nr ; Push the number to be checked before calling findPrime
call primeCheck
cmp eax, 1 ; Check the return value, prime if equal, otherwise keep searching
jne search10001
inc primes_found ; Increase primes_found with 1
cmp primes_found, 100 ; Check if the prime found is the 10001th, if not, start over
jl search10001

print "The 10001th prime is: "
print ustr$(current_nr)

ret
main endp

primeCheck proc current_nr:DWORD ; Function to check if a number is prime
local current_check :DWORD ; Local variable

mov current_check, 1 ; Initialize local variable

searchprime:
add current_check, 2
mov eax, current_nr ; Move current number into eax to prepare it for division
div current_check ; <--- THIS LINE REFUSES TO WORK. Comment it out and everything else works.


print ustr$(current_nr),13,10
mov eax, 1
ret 0 ; Clears the stack before returning
primeCheck endp

end start

dedndave

the dword form of the DIV instruction divides a qword dividend in EDX:EAX by a dword divisor
you should zero out EDX if you are not going to load a high dword into it
        xor     edx,edx
        div     current_check

Ani_Skywalker

Quote from: dedndave on October 30, 2011, 12:40:02 AM
the dword form of the DIV instruction divides a qword quotient in EDX:EAX by a dword divisor
you should zero out EDX if you are not going to load a high dword into it

I read about that in Intel Software Developers Manual, but could not figure out why it is like that? Shouldn't a DWORD fit into EAX? Both are 32 bits.

dedndave

you have another problem, here.....
       ret     0          ; Clears the stack before returning
primeCheck endp


you have a dword parameter on the stack that needs to be popped off (4 bytes)
       ret     4          ; Clears the stack before returning
primeCheck endp

dedndave

when you multiply 2 dwords together, the result can be as large as 64 bits
so - the inverse operation is to take a 64-bit value and divide it by a 32-bit value
this will leave you with a 32-bit quotient - and a 32-bit remainder

for the intel family processors, all divides work this way
the dividend is twice the width of the divisor

Ani_Skywalker

Quote from: dedndave on October 30, 2011, 12:57:46 AM
when you multiply 2 dwords together, the result can be as large as 64 bits
so - the inverse operation is to take a 64-bit value and divide it by a 32-bit value
this will leave you with a 32-bit quotient - and a 32-bit remainder

Not sure I understand that. Here are the questions that arises:

1. What would happen if I load the EDX with a high dword? In which cases would I like to do that?
2. Does the above mean I can find the quotient at edx and the reminder at eax? Or how is that paired up?

Ani_Skywalker

And more important, how do I formate my div-instruction if I want the reminder to be shown? Which I want :)


Ani_Skywalker

qWord: I've got those and I've read those. It does not provide code examples and from a noobs perspective it doesnt teach you either. It probably is a great guide for someone who already knows asm, but I'm trying to learn it still.

qWord

Quote from: Ani_Skywalker on October 30, 2011, 01:19:32 AM
And more important, how do I formate my div-instruction if I want the reminder to be shown? Which I want :)
mov ecx,divider
mov edx, dividend high DWORD
mov eax,dividend low DWORD
div ecx
;eax = quotient
;edx = reminder
FPU in a trice: SmplMath
It's that simple!

Ani_Skywalker

Does ecx have to be used? And what should I load into edx if my division is small to begin with but will grow and I need a DWORD for the late parts of my loop. A high-level sample just to show what I try to do, pretend we want to find all numbers below 100000000 that got 47 as a reminder when divided by 123:

for (i = 500; i<100000000; i++) {
if (i % 123 == 47) { printf("%d\n", i);}
}


I have following code in asm:

mov eax, tobedivided
xor edx, edx
div divider

print ustr$(eax)
print ustr$(edx)


Problem is, edx does not contain the reminder in that case and I cant figure out why?

qWord

Quote from: Ani_Skywalker on October 30, 2011, 01:49:11 AMprint ustr$(eax)
print ustr$(edx)


Problem is, edx does not contain the reminder in that case and I cant figure out why?
-->
Quotepush edx
print ustr$(eax)
pop edx
print ustr$(edx)
(alternatively use edi,esi or ebx (Win/IntelABI))
FPU in a trice: SmplMath
It's that simple!

Ani_Skywalker

qWord: Oh, thanks! I feel really dumb now. I always forget to push values before using macros. Sorry for taking your time with this. Entire second half of this thread was due to that   :(

dedndave

for DIV, the divisor can be in a register (like ECX), or it can be a memory operand   :U

let's take a couple examples to see how the upper dword works

we want to divide 4294967295 (0FFFFFFFFh) by 65536 (10000h)
notice that our dividend fits into 32 bits
but - we have room for 64 bits, so the actual dividend will be 00000000:FFFFFFFF
the upper part goes in EDX and the lower part goes in EAX
        mov     eax,0FFFFFFFFh ;low dword of dividend
        mov     edx,0          ;high dword of dividend
        mov     ecx,10000h     ;divisor
        div     ecx

after the DIV instruction, EDX will hold a remainder of 65535 (0FFFFh)
EAX will hold a quotient of 65535 (0FFFFh)

if we want to test it, we can reverse it
dividend = (quotient x divisor) + remainder

4294967295 = (65535 x 65536) + 65535

now, let's say we want to divide a slightly larger dividend
instead of 4294967295, we want to divide 4294967296
4294967296 is too large to fit into a 32 bit register (in hex, it is 00000001:00000000)
so........
        mov     eax,0          ;low dword of dividend
        mov     edx,1          ;high dword of dividend
        mov     ecx,10000h     ;divisor
        div     ecx

after the DIV instruction, EDX will hold a remainder of 0
EAX will hold a quotient of 65536 (10000h)

dividend = (quotient x divisor) + remainder

4294967296 = (65536 x 65536) + 0

dedndave

now - there are a couple things to watch out for when using DIV   :bg

i think you already saw one of them - "Divide Overflow"
this happens when the dividend is sufficiently large and the divisor is sufficiently small
it causes the resulting quotient to be too large to fit into the 32 bit register
        mov     eax,0FFFFFFFFh ;low dword of dividend
        mov     edx,0FFFFFFFFh ;high dword of dividend
        mov     ecx,10h        ;divisor
        div     ecx

divide overflow will occur because the quotient wants to be 0FFFFFFF:FFFFFFFF - way too large to fit into EAX   :P
you never have to worry about the remainder overflowing the size of EDX
that is because the largest possible remainder is one less than the divisor

the other problem that can occur is "Divide by Zero"
you must design your code so that the divisor will never be 0

these are fatal errors because the processor does not know how to recover