Population

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.