; Title GCD.asm ; Author: A.Pinck; modified by Sv. Ranev ; Date written: 3 November 1997, 20 March 2007 ; Purpose: ; Enter two numbers (unsigned, maximum of 4 decimal digits) ; Calculate and display their Greatest Common Divisor ; ; -Ian! D. Allen - idallen@idallen.ca - www.idallen.com ; ; This is .COM type program. ; Both the Code Segment (CS) and Data Segment (DS) are the same. GCD segment assume cs:GCD,ds:GCD org 100h start: mov dx,offset askFor1st mov ah,09 int 21h ;prompt for first number call getNum ;value returned in AX jc inDataErr ;Carry flag set if input invalid cmp ax,0 je inDataZero mov large,ax ;save value if OK mov dx,offset askFor2nd mov ah,09 int 21h ;prompt for second number call getNum jc inDataErr cmp ax,0 je inDataZero mov small,ax loop1: mov ax,large ;Loop until large and small are equal cmp ax,small jz done jnc reduce ;if large > small don't switch mov bx,small ;otherwise, switch large and small values mov small,ax mov large,bx reduce: mov ax,large ;reduce large by small amount sub ax,small mov large,ax jmp loop1 ;loop back done: call showNum mov al,00 ;no error indicator jmp exit ;--- error message handling --- inDataErr: mov dx,offset dataErr mov al,04 ;invalid data error code jmp showErr inDataZero: mov dx,offset dataZero mov al,02 ;zero data value code showErr: mov ah,09 int 21h ;issue error message ;------------------------------- exit: mov ah,4Ch ;terminate with code int 21h ;-- Data area -------------------------------------- large dw ? small dw ? askFor1st db 0Dh,0Ah,"Enter first number: $" askFor2nd db 0Dh,0Ah,"Enter second number: $" dataErr db 0Dh,0Ah,"Invalid/Non-numeric character in input.$" dataZero db 0Dh,0Ah,"Zero input data value is not legal.$" ;========================================== ; showNum displays the 2's complement number ; in AX as a decimal number showNum proc near push ax ;save working registers push bx push cx push dx push ax mov dx,offset newline ;ensure display is on a newline mov ah,09 int 21h pop ax cmp ax,0 ;test for negative jge positive;skip ahead if positive mov ah,02 ;display character code mov dl,'-' ; minus sign int 21h mov bx,ax sub ax,bx ;ax now zero sub ax,bx ;ax now positive positive: mov bx,10 ;divide by 10 to convert to decimal mov cl,0 ;count of number of digits produced div_loop: mov dx,0 ;setup to divide dx|ax by bx idiv bx ;unsigned division: ;quotient in ax, remainder in dx push dx ;save the digit (remainder) inc cl ;keep track of number of digits cmp ax,0 ;until nothing left to divide jnz div_loop; loop back show_digit: pop dx add dl,30h ;convert digit to ASCII code mov ah,02 ;display character int 21h dec cl ;loop until all digits shown jnz show_digit pop dx ;restore working registers pop cx pop bx pop ax ret ;-- local data -- newline db 0Dh,0Ah,"$" showNum endp ;========================================== ; getNum returns number input (converted to ; binary) in ax ; input is assumed to be a positive, decimal ; value with a maximum of 4 digits, terminated ; with a carriage return ; Carry flag is set (on) if an input error is ; detected (Carry flag is clear (off) if the ; input is valid getNum proc near push bx ;save working registers push cx push dx mov num,0 mov bh,'9' ;setup for valid range testing mov bl,'0' mov cl,4 ;maximum number of digits acceptable get_loop: mov ah,01 ;get key (with echo) int 21h cmp al,0Dh ;exit loop on carriage return je get_exit cmp bh,al ;check that it's < '9' jc bad_digit ;error if its not sub al,bl jc bad_digit ;error if its < '0' mov ah,0 push ax mov ax,num mov dx,10 ;decimal based system imul dx ;multiply ax by dx results in dx|ax mov num,ax ;value of prior digits times 10 pop ax ;add this digit's value add num,ax sub cl,1 jnc get_loop bad_digit: ;-- if we get here something is wrong ;-- by careful coding we have ensured that ;-- the carry flag will be set ;-- this is the "error" return indicator get_exit: mov ax,num pop dx ;restore working registers pop cx pop bx ret ;--- local data --- num dw ? getNum endp ;========================================== GCD ends end start