SQUAREROOT--A APPROACH BY BINARY SEARCH(2)
1。Improved edition.
It improved in several ways. It expand input limit to up to 65535. It uses a general "divide" function to generalize the call, deleting all those jump for 8bit and 16bit div. A modest improvement after all.
2. Main function
All other function remains the same as before except some simplicity by using "divide" function call.
A. divide
input: by stack dividant, divisor
output: by stack remainder, quotient
3. Problems & Doubts
It took me almost half painful day to debug a simple dividing problem: when the divisor is a quite small number, say 2, and it seems the assembler try to use 8bit div instead of 16bit even though the ax is a 16bit number. Because it continually give "divide overflow" error. It bothered me so painfully! And in book it only gives a vaguely explanation that this will trigger a 00h interrupt which is a hardware interrupt, it suggested that some application programmer may want to adapt this kind of error. But why? How can MASM assembler make this kind of mistake?
Personally I am still not 100% sure about this is the real reason. However, I called ChunMing and he hinted me to use shift to get round of this problem.
Another doubt is the previous program size is more than 2k, and now it is less 1k. It seems there is a big difference in assembling the two program.
4. My program
.DOSSEG
.MODEL SMALL
.STACK 200H
.DATA
MSG DB "THIS IS TRUE", "$"
MSG1 DB "THIS IS QUOTIENT", "$"
MSG2 DB "THIS IS REMAINDER", "$"
.CODE
START:
MOV AX, @DATA
MOV DS, AX
CALL INPUTNUMBER
CALL SQUAREROOT
CALL CHANGELINE
CALL DISPLAYNUMBER
MOV AX, 4C00H
INT 21H
;PASS DIVIDANT, DIVISOR BY STACK
;GET QUOTIENT FROM STACK
QUOTIENT PROC
PUSH BP
MOV BP, SP
PUSH AX
MOV AX, [BP+6]
PUSH AX
MOV AX, [BP+4]
PUSH AX
CALL DIVIDE
POP AX; USELESS REMAINDER, ONLY POP
POP AX; THIS IS QUOTIENT
MOV [BP+6], AX
POP AX; THE ORIGINAL AX SAVED
POP BP
RET 2
QUOTIENT ENDP
;PASS DIVIDANT, DIVISOR BY STACK
;GET MODULOS FROM STACK
MODULEPROC
PUSH BP
MOV BP, SP
PUSH AX
MOV AX, [BP+6]
PUSH AX
MOV AX, [BP+4]
PUSH AX
CALL DIVIDE
POP AX; THIS IS REMAINDER
MOV [BP+6], AX
POP AX; USELESS QUOTIENT, BUT HAVE TO POP OUT TO CLEAR STACK
POP AX; ORIGINAL AX SAVED
POP BP
RET 2
MODULEENDP
;USE STACK TO PASS DIVIDANT AND DIVISOR
;USE STACK TO RETURN QUOTIENT AND REMAINDER
DIVIDEPROC
PUSH BP
MOV BP, SP
PUSH AX
PUSH BX
PUSH DX
MOV AX, [BP+6]; THE DIVIDANT
MOV BX, [BP+4]; THE DIVISOR
CMP BH, 0; CHECK IF IT IS A 16BIT DIVIDE OR NOT
JNE SIXTEENDIV
CMP AH, 0
JNE SIXTEENDIV
EIGHTDIV:
DIV BL; 8BIT DIV
MOV [BP+6], AL; THE QUOTIENT;
MOV [BP+4], AH; THE REMAINDER
JMP ENDDIV
SIXTEENDIV:
DIV BX ; 16BIT DIV
MOV [BP+6], AX; THE QUOTIENT
MOV [BP+4], DX; THE REMAINDER
ENDDIV:
POP DX
POP BX
POP AX
POP BP
RET
DIVIDE ENDP
CHANGELINE PROC
PUSH AX
PUSH DX
MOV AH, 02
MOV DL, 0DH
INT 21H
MOV DL, 0AH
INT 21H
POP DX
POP AX
RET
CHANGELINE ENDP
DISPLAYNUMBERPROC
PUSH BX
PUSH CX
PUSH DX
MOV BX, 10
MOV CX, 0
BEGINDIVIDE:
CMP AX, 0
JE SHOWRESULT
PUSH AX
PUSH BX
CALL DIVIDE
POP DX
POP AX
INC CX
ADD DX, 30H
PUSH DX
JMP BEGINDIVIDE
SHOWRESULT:
CMP CX, 0
JE ENDDISPLAY
DISPLAYLOOP:
MOV AH, 02H
POP DX
INT 21H
LOOP DISPLAYLOOP
ENDDISPLAY:
POP DX
POP CX
POP BX
RET
DISPLAYNUMBERENDP
SQUAREROOT PROC
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
MOV CX, 00H
MOV BX, AX; BX SAVE THE NUMBER
CMP BX, 255; THE BIGGEST ROOT OF 16BIT
JG LOCAL1
MOV DI, BX
JMP LOCAL2
LOCAL1:
MOV DI, 255; THIS IS UPPER BOUND OF 16BIT ROOT
LOCAL2:
MOV SI, 1; LOWBOUND
CHECKRESULT:
MOV AX, SI
ADD AX, DI ; AX IS THE SUM OF LOW AND HIGH BOUND
MOV DX, 02H
SHR AX, 1
MOV CX, AX
MUL AX; AX IS THE SQUARE OF CX
COMPARE:
CMP AX, BX
JE FINDRESULT
CMP AX, BX
JB SMALLER
BIGGERR:
DEC CX
CMP CX, SI; COMPARE LOWBOUND
JL FINDRESULT; EXCEED LOW BOUND
MOV DI, CX;NEW HIGH BOUND
JMP NEXT
SMALLER:
INC CX
CMP CX, DI; COMPARE HIGHBOUND
JG FINDRESULT ; EXCEED LOW BOUND
MOV SI, CX; NEW LOW BOUND
JMP NEXT
NEXT:
JMP CHECKRESULT
FINDRESULT:
MOV AX, CX; RESULT IS RETURN IN AX
POP DI
POP SI
POP DX
POP CX
POP BX
RET
SQUAREROOT ENDP
INPUTNUMBER PROC
PUSH BX
PUSH CX
MOV AX, 00H
MOV BX, 00H
MOV CX, 00H
CHECK:
MOV AH, 01H
INT 21H
CMP AL, 0DH
JE ENDINPUT
MOV CL, AL; SAVE INPUT IN CX
MOV AX, 10; PREPARE MUL
MUL BX ; OLD DATA IN BX
SUB CX, 30H; CX TO BE NUBMERS
ADD AX, CX
MOV BX, AX; SAVE DATA IN BX
JMP CHECK
ENDINPUT:
MOV AX, BX; RETURN VALUE IN AX
POP CX
POP BX
RET
INPUTNUMBER ENDP
END START
END
Click here to download the execute file to have a try. Just run and key in a number smaller than 65535 ended by return and you get the approximate answer or exact answer, depending if the number has an integer root or not.