1

EDIT: the code now runs,thanks for the assistance. it may not be pretty but it works

I have to write a program that finds the GCD of two numbers, the prompt reads like this. "You are to write a program containing a function which will evaluate the Greatest Common Divisor function using Euclid’s algorithm, defined as follows:

      GCD(a,0) = a 
      GCD(a,b) = GCD(b, a mod b) for b > 0

Your function is to compute GCD(a,b) recursively and return the value in ax. Input to the function should be accomplished by pushing the values of a and b on the stack.

Your main program will:

print a program description on the screen display a prompt on the screen accept values for a and b from the keyboard (Use the DEC_IN procedure you wrote previously.) pass the values of a and b to the function print out the value of GCD(a,b) with an appropriate prompt (Use the DEC_OUT procedure you wrote previously.) Ask the user if he wishes to repeat the process." I believe I have accomplished most of the objectives but when run my program just freezes after entering the second integer. any help would be greatly appreciated here is my code:

; program to calculate gcd of two inputs
    org 100h
section .data
prompt0: db "This is a program to caculate the GCD of two inputs $"
prompt1: db "Please enter integer X: $"
prompt2: db "Please enter integer Y: $"
prompt3: db "The GCD is:    $"
intX     dw 0
intY     dw 0
gcd      dw 0

section .text
    mov ah,9        ; print prompt
    mov dx,prompt0
    int     21h
    mov ah,9        ; print prompt
    mov dx,prompt1
    int     21h
    call    dec_in      ; read value into bx
    mov [intX], bx
    mov ah,9        ; print prompt
    mov dx,prompt2
    int     21h
    call    dec_in      ; read value into bx
    mov [intY], bx
    call    calc_GCD
    mov     bx, [gcd]
    mov ah,9        ; print output label
    mov dx,prompt3
    int     21h
    call    dec_out     ; display the value in bx (gcd)

dec_in: 
    ; save registers
    push    ax
    push    dx

    xor bx,bx       ; bx holds accumulated input
    mov ah,1        ; read char fcn
    int 21h     ; read it into al
while1: 
    cmp al,0Dh      ; char = CR?
    je  finis       ; if so, we are done
    push    ax      ; save the character read
    mov ax,10       ; set up for multiply
    mul bx      ; dx:ax <- bx * 10
    mov bx,ax       ; put 16-bit result back in bx (assume no overflow)
    pop ax      ; restore the char read
    and ax,000Fh    ; convert character '0'-'9' to value 0-9
    add bx,ax       ; add value to accumulated input
    mov ah,1        ; read char fcn
    int 21h     ; read next char into al
    jmp while1      ; loop until done
finis:  
    ; restore registers
    pop dx
    pop ax
    ret

dec_out:
    ; save registers we will be using
    push    ax
    push    bx
    push    cx
    push    dx

    xor cx,cx       ; cx counts digits, initially zero
rept:
    mov ax,bx       ; set up to divide by by 10
    xor dx,dx       ; must have a 32 bit (unsigned) dividend
    mov bx,10       ; divisor will be in bx
    div bx      ; quotient will be in ax, remainder in dx
    push    dx      ; push remainder on stack
    inc cx      ; we generated another digit, so count it
    mov bx,ax       ; the quotient goes back in bx
    cmp ax,0        ; clever way to test if quotient is zero
    jne rept        ; if not, generate next digit
    mov ah,2        ; display character function
for2:               ; loop cx times
    pop dx      ; pop digit to print
    or  dl,30h      ; convert the digit to print to ASCII code
    int 21h     ; display the character
    loop    for2        ; and keep going until all digits displayed

    ; restore registers
    pop dx
    pop cx
    pop bx
    pop ax
    ret

calc_GCD:
    mov   ax, [intY]        
        cmp   ax, 0       
        jne   chk_swap      ; check if swap is needed
        mov   ax, [intX]    
        mov   [gcd], ax ; move result into gcd
        ret
chk_swap:
         mov   ax, [intX]   ;store 
         mov   bx, [intY]   
         cmp   ax, bx       
         jl    swap     
         jnl   loop     
swap:
      mov   ax, [intX]      
      mov   bx, [intY]      
          ;temp
          mov   cx, [intY]      
      ; intY = intX
          ; intX = temp
          mov   bx, ax      
          mov   ax, cx      
          mov   [intX], ax      
          mov   [intY], bx      
          jmp   loop            
loop:
          mov   dx, [intX]      
          shr   dx, 16      
          mov   ax, [intX]      
          mov   bx, [intY]      
          div   bx          
          mov   di, [intX]      
          mov   si, [intY]      
          mov   di, si      
          mov   [intX], di      
          mov   [intY], dx      
          jmp   calc_GCD        
Herebutnot
  • 19
  • 1
  • 4
  • 2
    Have you stepped through it with a debugger? Turbo debugger works really well, but you can also use debug.exe (the DOS debugger). – Michael Petch Dec 02 '15 at 03:14
  • 1
    `mov eax, [intX] ;store ` – Mike Nakis Dec 02 '15 at 03:28
  • 1
    `jl swap` immediately followed by `jnl loop` is not indicative of great craftsmanship. Remove `jl swap`. – Mike Nakis Dec 02 '15 at 03:32
  • 1
    I can tell you this, I find it unusual you are creating a 16-bit DOS application using 32 bit registers. Although this will work on some hardware it surely won't work on a real 8086. I'm going to give you a hint though. If you do `div bx` like you are doing in `loop` that takes the combined 32 bit value of DX:AX and divides it by _BX_. If the quotient of that division can't be represented in 16 bits it will throw a division exception and likely hang. – Michael Petch Dec 02 '15 at 03:32
  • 2
    `jmp loop` immediately followed by `loop:` is also not indicative of great craftsmanship. – Mike Nakis Dec 02 '15 at 03:33
  • 1
    Unfortunately, the code is a bit too complicated to follow and find what is wrong with it. I give up. No matter what the problem is, kudos, you have gone a long way already by writing this much assembly. I would recommend that you heed @MichaelPetch's advice. Writing code is only half of programming; the other half is debugging code. – Mike Nakis Dec 02 '15 at 03:36
  • 2
    There are enough issues with this code, that I doubt that giving you working code is the best solution for you to learn what you need to. I think this question and code is better suited to have a teacher assistant or a professor for your class to sit down and point you to the course material you need to understand to rewrite the code properly. – Michael Petch Dec 02 '15 at 03:39
  • No, I did not know a way to debug with assembly language, I am in a college course and my professor has left out a lot of information, most of what I have learned was self taught but I still have major gaps in my understanding. by what I understand from your above comments I should not be using the eax, ebx and exc registers. I thought I had used them correctly, but I will try to change them in order to prevent an exception. also I realize my comments are poor /non existant in the last portion, I have written and deleted that portion more than 5 times now and gave up writing comments. – Herebutnot Dec 02 '15 at 03:48
  • @MichaelPetch I agree and if this course had a t/a I would defiantly ask for their help, the professor has no office hours this week as it is the week before finals and he is out of town, and no one in the tutoring center knows assembly language. I was kind of using this as a last resort sadly, but I really appreciate your comments and I will try to implement them as best I can, by any chance would you know a link for turbo debugger? I searched for it and found a lot of sketchy sites and it is no longer available from http://www.borland.com/bcppbuilder/turbodebugger/ – Herebutnot Dec 02 '15 at 03:59
  • If *your professor has left out a lot of information*, you need to ask your professor to provide it. Your tuition pays for you to be provided an education, and if your professor hasn't yet provided it then they have not yet earned their pay. Ask for help and get what you have paid to receive. – Ken White Dec 02 '15 at 04:07
  • yes i have done that, he just points to the online resource of around 400 powerpoint slides. Either way he is inaccessible until the final next week. – Herebutnot Dec 02 '15 at 04:10
  • thanks @MichaelPetch for that tip, turns out it was the exception. the code now works – Herebutnot Dec 02 '15 at 04:20

1 Answers1

1

There's no need to swap for GCD. If the divisor is greater than the dividend, the quotient is zero and the remainder is the dividend, so the first step of GCD will do the swap automatically if it's needed.

There's no need to keep storing the intermediate results into intX and intY. Just use registers to calculate the GCD until you get a remainder of 0, then the previous remainder is the GCD.

;                                       ;ax, bx contain the two numbers
gcd0:   xor     dx,dx                   ;divide
        div     bx
        mov     ax,bx                   ;ax = new dividend = old divisor
        mov     bx,dx                   ;bx = new remainder
        test    bx,bx                   ;loop if remainder != 0
        jnz     gcd0
;                                       ;ax = gcd

maximum number of loops is Fibonacci numbers: 46368, 28657, gcd = 1

rcgldr
  • 23,179
  • 3
  • 24
  • 50