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 MODULE PROC 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 MODULE ENDP ;USE STACK TO PASS DIVIDANT AND DIVISOR ;USE STACK TO RETURN QUOTIENT AND REMAINDER DIVIDE PROC 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 DISPLAYNUMBER PROC 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 DISPLAYNUMBER ENDP 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.
本文地址:http://com.8s8s.com/it/it29330.htm