News:

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

any issues with div

Started by ninjarider, July 04, 2007, 08:10:04 PM

Previous topic - Next topic

ninjarider

i've been working on some code yesturday that has a div statment. when i ran the code it was comming up in a division by 0 error. ran debug and all the registers that i was using were non zero. for cracks and gigs i added an xor dx, dx statment. is there any reason that dx needs to be 0 for the div instruction to function normally of a p4.

Tedd

(e)dx makes up the upper 32-bits of the 64-bit operand to be divided, so it should be set to zero in any case :P
Also, if the result won't fit into 32-bit then you'll get an exception.
No snowflake in an avalanche feels responsible.

raymond

QuoteAlso, if the result won't fit into 32-bit then you'll get an exception.

The main - and only - criteria is that the result must fit into 32 bits. EDX does not necessarily need to be 0 as long as the divisor is smaller than the content of EDX. When dividing by a 32-bit value, you are effectively dividing the 64-bit value in the EDX:EAX pair.

(When dividing by a 16-bit value, you are dividing the 32-bit value in the DX:AX pair, and when dividing by an 8-bit value, you are dividing the 16-bit value in the AH:AL pair also known as AX.)

Raymond
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

dsouza123

The divisor needs to be bigger than EDX.

<code>
  mov edx, 4     ; 64 bit dividend edx:eax pair, eax lower 32 bits
  mov eax, 11
  mov ecx, 5     ; 32 bit divisor
  div ecx
  mov quo, eax   ; 3435973838  or in hex 0CCCCCCCEh  quotient
  mov rem, edx   ; 1 remainder
</code>

OK because ecx > edx.

raleeper

Quote from: dsouza123 on July 05, 2007, 11:51:55 AM
The divisor needs to be bigger than EDX.

The Intel manual doesn't mention this restriction.  So what happens on, eg,

    edx:eax <- 20:0
    ecx <- 10
    div ecx

ie, 2000000000\10    the result should be

    0200000000.

But 0200000000 = 02,0000,0000.

is too big for eax, so I guess that explains it.

Thanks.






dsouza123

The jist of some example code, source and exe in the zipped attachment.


.data
  ddn dd  1, 20   ; dividend
  dsr dd 10       ; divisor     the values do division 10 twice  30 once
  quo dd  0,  0   ; quotient
  rem dd  0       ; remainder

.code
start:
  mov edx, ddn+4
  mov eax, ddn
  mov ecx, dsr
  .if ecx > 0
    .if ecx > edx
       div ecx
       mov quo, eax
       mov rem, edx
    .else
       mov eax, edx
       mov edx, 0
       div ecx
       mov quo+4, eax
       ; edx already has the remainder that is now the upper 32 bits
       mov eax, ddn
       div ecx
       mov quo, eax
       mov rem, edx
       invoke MessageBox,0,addr szTBig,addr szCapt,MB_OK
    .endif
    invoke wsprintf,addr szQR,addr szFmt, ddn+4, ddn, dsr, quo+4, quo, rem
    invoke MessageBox,0,addr szQR,addr szCapt,MB_OK
  .else
     invoke MessageBox,0,addr szZero,addr szCapt,MB_OK
  .endif

[attachment deleted by admin]

Shantanu Gadgil

Quote
QuoteThe divisor needs to be bigger than EDX.

The Intel manual doesn't mention this restriction.  So what happens on, eg,

There is no such limit ... what dsouza123 was trying to show is:

The edx:eax pair which can be seen as:
( (4 GB  * x ) + y ) / z
where z > x
and
y < 4GB
will always yield a number < 4GB

4GB here corresponds to the 32bit thing ... would be similar for lesser bit values (16bit, 8 bit, etc.)

Hope that explains it a bit!

Regards,
Shantanu
To ret is human, to jmp divine!

dsouza123

The divisor needs to be bigger than EDX, is a practical rule of thumb.

Using it prevents both division by zero and an overflow of the 32 bit quotient exceptions.

With a Non Zero divisor that is less than or equal to EDX
the resulting quotient will be bigger than 32 bits and needs two divisions
and storage big enough to hold the result (quotient), 64 bits will work.

The first division using the upper 32 bits of the dividend as the lower 32 bits with 0 in the upper,
the quotient becomes the upper 32 bits of the final quotient and the remainder
the new upper 32 bits of the dividend along with the original lower 32 bits.
The second division produces the lower 32 bits of the quotient and the remainder is the remainder.

Example
mov edx, 8  ; upper 32 bits dividend
mov eax, 3  ; lower 32 bits dividend
mov ecx, 4  ; 32 bit divisor

ecx <= edx so two divisions are needed

mov edx, 0
mov eax, 8
mov ecx, 4
div ecx

mov quo+4, eax  ; 2 for upper 32 bits of final quotient
edx has the revised upper 32 bits of dividend
mov eax, 3
mov ecx, 4
div ecx

mov quo, eax  ; lower 32 bits of quotient
mov rem, edx  ; 32 bit remainder

As long as the divisor is non zero the two divisions can always be done.

dsouza123

The divisor really needs to be bigger than EDX, to prevent a division exception.


If the divisor <= edx a division exception will occur
either division by zero or quotient overflow.

If the divisor > edx the division will execute
and eax will hold the quotient, edx the remainder.

x  any value
2+ always bigger than 1+
1+ all but zero
0  zero

edx the upper 32 bits of the dividend
eax the lower 32 bits of the dividend
ecx the 32 bit divisor

edx:eax ecx
x : x   0   ; ecx == 0   causes a division (by zero) exception

can combine the following two with test  if ecx > edx
0 : x   1+  ; ecx > edx  one division, quotient 32 bit, remainder 32 bit
             ; effectively a 32 bit by 32 bit division

1+: x   2+  ; ecx > edx  one division, quotient 32 bit, remainder 32 bit


1+: x   1+  ; ecx <= edx causes a division overflow exception  BUT  can be prevented by
             ; two divisions, final quotient 33+ bit, remainder 32 bit