Herebutnot
Herebutnot

Reputation: 19

Program to find GCD in x86 assembly language

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        

Upvotes: 1

Views: 10963

Answers (1)

rcgldr
rcgldr

Reputation: 28921

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

Upvotes: 2

Related Questions