; GCD.asm ; Author: A.Pinck ; Date written: 3 November 1997 ; Purpose: ; Enter two numbers (unsigned, maximum of 4 decimal digits) ; Calculate and display their Greatest Common Divisor 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 while: 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 while ;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 ;------------------------------- 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 push bx push cx push dx cmp ax,0 ;test for negative jp 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 mov dx,offset newline ;ensure display is on a newline mov ah,09 int 21h 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 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 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 dec cl 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 pop cx pop bx ret ;--- local data --- num dw ? getNum endp ;========================================== GCD EndS End start