My program's supposed to perform division by using subtraction. However, I'm getting nonsense results as output. Could someone help me with my procedure and the loop within? Thank you.

div proc
pushad

mov ecx,firstInt
mov ebx,0
subtracting:
    sub ebx,secondInt
loop subtracting
mov divResult,ebx
popad
ret
divt endp

1 Answers

2
Sep Roland On Best Solutions

You continu subtracting for as long as there is no borrow. If a borrow happened, you have the count:

    mov     ecx, firstInt
    mov     ebx, -1
subtracting:
    inc     ebx
    sub     ecx, secondInt
    jnb     subtracting
    mov     divResult, ebx

EDIT

What the above code still lacks is checking if the divider is zero. If we allow a zero-divider the code will run forever because subtracting zero will never produce a borrow!

This simple solution gets the job done, but it is unacceptably slow for big quotients. This calls for a better solution without betraying of course the task of "Division by using subtracting" aka "Don't use div (or any similar instruction)".

In order to mimic the div instruction:

divide:
    mov     eax, firstInt
    xor     edx, edx
    div     secondInt       ; -> EDX is remainder, EAX is quotient

we can write:

simple:
    mov     edx, firstInt
    mov     eax, -1
.A: inc     eax
    sub     edx, secondInt
    jnb     .A
    add     edx, secondInt  ; -> EDX is remainder, EAX is quotient

The problem with this simple solution is that we could be subtracting a small number many, many times. What if we could find a way to subtract more at once?
We can, if we subtract binary multiples of the divider (*1, *2, *4, *8, *16, ...). It will be the summing of these factors that produces the quotient.

To calculate e.g. 503 / 20 we would subtract the following:

503 - (20 * 16) = 183
183 - (20 *  8) =  23
 23 - (20 *  1) =   3 <-- is remainder
            --
            25 <-- is quotient

In code:

complex:
    mov     edx, firstInt
    xor     eax, eax
    jmp     .C
.A: rol     ecx, 1
    shl     ebx, 1
    jc      .B
    cmp     ebx, edx
    jbe     .A
.B: rcr     ebx, 1
    add     eax, ecx
    sub     edx, ebx
.C: mov     ebx, secondInt
    mov     ecx, 80000000h
    cmp     edx, ebx
    jnb     .A
; -> EDX is remainder, EAX is quotient

To illustrate the importance of developing a better solution, I've timed a few divisions:

                       simple      complex    divide
                   --------------  --------  --------
4294967295 /   1   8087730.0 µsec  3.0 µsec  0.3 µsec
2147483648 /  10    405994.0 µsec  1.3 µsec  0.1 µsec
     47623 / 320         0.4 µsec  0.2 µsec  0.1 µsec
  • 4294967295 / 1 is the worst case division
  • 2147483648 / 10 is used to start displaying the number 2147483648
  • 47623 / 320 is used to convert a 320x200 256-color video mode offset address 47623 into (x,y) coordinates