用x86汇编语言查找GCD的程序

时间:2015-12-02 03:11:06

标签: assembly nasm dos

编辑:代码现在运行,感谢您的帮助。它可能不漂亮,但它的工作原理

我必须编写一个找到两个数字的GCD的程序,提示符如下所示。 "你要编写一个包含函数的程序,该函数将使用欧几里德算法评估最大公约数函数,定义如下:

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

你的功能是递归计算GCD(a,b)并返回ax中的值。应该通过按下堆栈上a和b的值来完成对函数的输入。

您的主程序将:

在屏幕上打印程序说明 在屏幕上显示提示 从键盘接受a和b的值(使用您之前编写的DEC_IN过程。) 将a和b的值传递给函数 使用适当的提示打印出GCD(a,b)的值(使用您之前编写的DEC_OUT过程。) 询问用户是否希望重复该过程。" 我相信我已经完成了大部分目标但是在运行我的程序时只需在输入第二个整数后冻结。 任何帮助将不胜感激 这是我的代码:

; 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        

1 个答案:

答案 0 :(得分:1)

没有必要换掉GCD。如果除数大于被除数,则商为零,余数为被除数,因此如果需要,GCD的第一步将自动进行交换。

无需将中间结果存储到intX和intY中。只需使用寄存器来计算GCD,直到得到0的余数,然后前一个余数就是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

最大循环数是Fibonacci数:46368,28657,gcd = 1