News:

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

Weird behavior from DIV

Started by Hjortur, September 01, 2008, 12:59:33 PM

Previous topic - Next topic

Hjortur

I decided to do the problems at projecteuler.net.   When i wrote this code, that is supposed to solve problem 1, it crashes. 
The thing is it doesnt crash until 3rd iteration and it does crash at the div cx instruction.  To fix that one i had to constantly set MOV edx, 0 at the start of every loop. 
Do you know why the program crashes without mov edx,0  ?
Also another one, when ebp reaches 4, ebp contains the number to be tested, i do this:
mov eax, ebp
div bx     ; <---  bx containing 5

i get dx == 0.  When it is clearly supposed to be 4 .  4%5 = 4 not 0
It does the same thing when the counter reaches 19, it thinks 19%5 =0 when it is 4.  :dazzled:
I also get the same results if i use idiv instead of div

Do you know why it is not working for me.  I am running amd64 dualcore (i dont remember the name).

p.s. when i run the prog in the computers at school, i get different results then at home ?? ......spooky....  :dazzled:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

;                      Project Euler Problem 1.
;       Find the sum of all the multiples of 3 or 5 below 1000.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    .486
    .model flat, stdcall
    option casemap :none
    include \masm32\include\windows.inc
    include \masm32\macros\macros.asm


    include \masm32\include\masm32.inc
    include \masm32\include\gdi32.inc
    include \masm32\include\user32.inc
    include \masm32\include\kernel32.inc


    include \masm32\include\debug.inc
    includelib \masm32\lib\debug.lib


    includelib \masm32\lib\masm32.lib
    includelib \masm32\lib\gdi32.lib
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib

    .data
sum dd 0



    .code

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

start:
    call main
    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

main proc
mov ebp, 1
mov ecx, 3
mov ebx, 5
mov edx, 0
loopstart:

mov dx, 0     ;   <---------*************************  if this is not here

cmp ebp, 1000
je done
mov eax, ebp
;PrintDec edx, "edx value"
idiv cx ;      <-----------------**********************  this fails here at third iteration
;PrintDec edx, "edx value"
test dx,dx
jnz @f
add sum, ebp
inc ebp
jmp loopstart
@@:
mov eax, ebp
idiv bx
test dx,dx
jnz @f
add sum, ebp
@@:
inc ebp
jmp loopstart
done:
print str$(ebp)
print chr$(13,10)
mov eax, sum
print str$(eax)
ret
main endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start


Whew! long time since I've posted anything here!

BogdanOntanu

The DIV ECX instruction will divide the contents of EDX:EAX register pair (64 bits) with content of ECX register (32bits)
The DIV CX instruction will divide the contents of DX:AX register pair (32 bits) with content of CX register (16 bits)

As you can "clearely" see from above the value of EDX or DX before the DIV is important and has a meaning. YES you usually have to clear DX or EDX before performing a division or you will have problems.

Also take care because if EDX:EAX or DX:AX are too big for the result to fit EAX or AX respectively.... then an exception will occur.

Division opcode is not to be treated "lightly"... when in doubt read the Intel CPU manuals ;) .

And another advice: using 16 bits style instructions in an 32bit envinornment (win32)  is a receipt for problems and usually it is also slowing down your code. Upgrade your way of thinking to the 32 bits style at least.

And usually EBP is used for stack frames inside PROC's. IT might not be a problem for this code but until you get experience with stack frames and local variables  it will be better if you do not use EBP explicitly in your code inside a MASM  PROC.
Ambition is a lame excuse for the ones not brave enough to be lazy.
http://www.oby.ro

Hjortur

Now when you say it, it somehow is so obvius.  :bg
I did read the intel manuals last night when I was trying to get to the bottom of this, but somehow I missed that point about EDX:EAX getting divided. 
I just needed someone to tell me this. 
But it still doesnt explain why I get different different results at school, at home i get 233677 or sum and at school i get 166833.
How could I solve this problem without messing around with 16-bit style instruction ?

PBrennick

Varying results? It is because you are using the base pointer without preserving it first, see below:

Avoid using ebp also, it is not necessary to do so as your algo is not register intensive and ebp has other purposes that can cause unexpected/variable results. Read up about Base Pointers in procedures in the win32 environment or just do a push ebp at the start and then pop it at the end. PUSHAD and POPAD can accomplish this and more, also.

loopstart: should be moved up one line and thusly making mov dx, 0 unnecessary.


mov ebx, 5
loopstart:
mov edx, 0
cmp ebp, 1000
je done


-- Paul
The GeneSys Project is available from:
The Repository or My crappy website

sinsi

Watch out for DIV (unsigned) and IDIV (signed, which is what your code uses).

Quote from: BogdanOntanu on September 01, 2008, 01:25:48 PM
And another advice: using 16 bits style instructions in an 32bit envinornment (win32) is a receipt for problems and usually it is also slowing down your code. Upgrade your way of thinking to the 32 bits style at least.
Yes, always use 32-bit registers if you can (but leave EBP until you understand what PROC does).

;       Find the sum of all the multiples of 3 or 5 below 1000.
Hah, I've only just realised what the code is supposed to do... :bdg
Light travels faster than sound, that's why some people seem bright until you hear them.

Hjortur

Pbrennick, I know i could have moved loopstart up once to eliminate one mov, but i first coded the loop without the mov dx,0 and all the registers up before the loop.
The mov dx,0 inside the loop was a patchwork to make it not crash, i was always commenting it in and out for varius testing, that is why there are two instructions doing
the same thing at the start.
But anyway, i thought that eax, ebx, ecx, edx, edi , esi, ebp and esp were all preserved through context swithces so it tought it would be save to use ebp
without preserving it, plus I am not using locals or the stack inside the proc so I dont see the problem why i could not use ebp.

But Bogdan suggested not using 16-bit style instruction, and I dont want to use the fpu to divide two numbers, do you have an idea how I could solve
this without using DIV ?

Sinsi:  Yeah i know about div and idiv, i tried using both, same results.  It is just a coincidence you got the idiv version.

BogdanOntanu

I have only suggested that you do not use 16 bit instructions and registers like DIV CX instead of DIV ECX. I have not suggested that DIV is in anyway a 16 bits instruction and you should not use it :P

Try to understand better what people say and what manuals write ...  otherwise you will always need somebody to "tell" you the truth ;)

Context switches have nothing to do with your problems here. Why do you bring more complex concepts to this topic?

EBP might or might not be in use by MASM inside a PROC even if you do not use locals or arguments. It is not under your control and hence you are playing with fire, the advices are given with good intention and not only for this case but also for your future learning and experiments. We saw you using EBP inside a PROC and that is simply not a good practice for a beginner.

If you fight the suggestions made by people that try to help you then it means that you know better. If you know better then why do you ask in the first place?

Ambition is a lame excuse for the ones not brave enough to be lazy.
http://www.oby.ro

Hjortur

QuoteIf you fight the suggestions made by people that try to help you then it means that you know better. If you know better then why do you ask in the first place?

I am very sorry if the way i write comes out as if i am fighting your suggestions.  English is not my native language so my maybe my thoughts dont show up is I intended them.
I am very pleased with you helping me and I do try to learn from you.    :bg

QuoteContext switches have nothing to do with your problems here. Why do you bring more complex concepts to this topic?
Sorry I thought pbrennic was referinng to that one when he said that i was not preserving ebp. 

I will keep the "dont play with ebp" in my mind when i will fix the code tonight and do some other project euler problems.

hutch--

Hjortur,

Most of it has already been said but the basic problem before you even write the code is you are not preserving the appropriate registers. You can freely use EAX ECX EDX but if you want to use more you can preserve EBX ESI EDI which colectively give you six registers to work with. If you know how to write a procedure without a stack frame you can then use EBP but must preserve it first and if you are really desperate and know how to do it you can even use ESP but its very risky to do so.

As a general sugestion, write your normal proc using local variables first, when you have it working start replacing the locals with registers and if you have some speed advantage by using the extra register, remove the stack frame to get EBP as well.

A normal proc would look like this.


yourproc args etc .....

    push ebx
    push esi
    push edi

  ; write your code here

    pop edi
    pop esi
    pop ebx

    ret

yourproc endp
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

dsouza123

Slightly modified (fixed) version.

The premise isn't clear, is it equivalent to having a list of the integers 1 to 999
removing any that aren't a multiple of 3, then continue removing any that are not multiples of 5,
then summing the resulting numbers in the list.
Multiples of both 3 and 5 are counted once.

Or a list of the integers 1 to 999 removing any that aren't a multiple of 3, sum the list.
Then a new list of the integers 1 to 999 removing any that aren't a multiple of 5, sum the list.
Add the two sums together.
Multiples of both 3 and 5 are counted twice.

Examples 15, 30 both are multiples of both 3 and 5, should they counted once or twice.


main proc

    push eax
    push ecx
    push edx
    push ebx
    push esi        ;  use esi instead of ebp
    push edi

    mov esi, 1      ;  current number
    mov ecx, 3
    mov ebx, 5

loopstart:
    mov edx, 0      ;   <---------*************************  if this is not here
    cmp esi, 1000
    je done
    mov eax, esi
    div ecx
    test edx,edx    ; 0 remainder means evenly divided  it is a multiple
    jnz @f
    add sum, esi
    inc esi         ; what about 15 a multiple of 3 and 5, should it be counted (once DID THIS) or twice
    jmp loopstart
@@:
    mov edx, 0      ; need 0, because remainders from earlier div may not be 0
    mov eax, esi
    div ebx
    test edx,edx
    jnz @f
    add sum, esi
@@:
    inc esi
    jmp loopstart

done:
    print str$(esi)
    print chr$(13,10)
    mov eax, sum
    print str$(eax)

    pop edi
    pop esi
    pop ebx
    pop edx
    pop ecx
    pop eax

    ret
main endp

[attachment deleted by admin]

raymond

I've been a Project Euler fan myself almost since the beginning (I've also become one of it's administrators). I have therefore written many programs to solve those problems and I have NEVER preserved ebx, esi, edi, nor epb when I needed those registers.

Rule #1: I never use any "proc" in those short programs (most under 2k).
For example, your first two instructions
start:
    call main
    exit

are completely useless. Such a start is probably a left-over from some HLL coding requirement. Write your code from the "start:" position. Then, use "invoke ExitProcess,0" or simply the "exit" macro whenever you want to exit your program.

If there's some segment of code you need to repeat more than once, either copy/paste it or write it as a "subroutine" which you simply "call" without passing arguments but use register or global memory contents as input. (This may be a difficult concept for those having learned some HLL first but used to be a standard way of coding in the old DOS days.)

And, if you don't have enough registers, remember that memory variables can often be used to provide the same service, albeit slightly slower in some cases. Example:
.data
  d3    dd  3
  d5    dd  5

.code
  mov  eax,1234
  xor  edx,edx
  div  d3           ;divide by 3
  test edx,edx
  ...


Good luck with Project Euler. Your math skills will definitely improve if you glean the forums and/or any available overview after solving each problem. Your coding skills should also improve.
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

RuiLoureiro

Quote from: dsouza123 on September 03, 2008, 11:37:22 PM
Examples 15, 30 both are multiples of both 3 and 5, should they counted once or twice.

Hi dsouza123,
                    in my opinion once: we take one, if it is multiple of 3 then sum goto the next;
                    No, then if it is multiple of 5 then sum goto the next. No, goto the next.
                    It is a logic question. To me, that OR imply this.
Rui