home *** CD-ROM | disk | FTP | other *** search
-
-
- ;Listing 1 - Square root algorithm plus code to benchmark and test it.
- ;
- INT_ROOT SEGMENT
- ASSUME CS:INT_ROOT
- ;
- CALC_ROOT PROC NEAR
- ;----------------------------------------------;
- ; Argument passed in BX. ;
- ; Root returned in BX. ;
- ; All registers except BX preserved. ;
- ;----------------------------------------------;
- PUSH AX
- PUSH CX
- MOV AX,BX ;Hold argument in AX.
- OR BH,BH
- JNZ GE_256
- CMP BL,1 ;If arg is zero or one,
- JBE GOT_ROOT ;then root = argument.
- MOV CL,4 ;If 2 <= argument <= 255
- SHR BL,CL ;then guess = 3 + arg/16.
- ADD BL,3
- JMP SHORT NEWTON
- GE_256: MOV BL,BH
- MOV BH,0
- JS GE_32768
- CMP BL,16
- JAE GE_4096
- SHL BL,1 ;If 256 <= argument <= 4095
- SHL BL,1 ;then guess=13+4*(arg hi byte).
- ADD BL,13
- JMP SHORT NEWTON
- GE_4096: ADD BL,50 ;If 4096 <= argument <= 32767
- JMP SHORT NEWTON ;then guess = 50 + arg hi byte
- GE_32768: CMP BL,255 ;If arg hi byte=255 then root=255.
- JZ GOT_ROOT ;This prevents ovflow by DIV.
- ADD BL,40 ;If 32768 <= argument <= 65279
- JNC NEWTON ;then guess = 40 + arg hi byte.
- MOV BL,255 ;Guess must never exceed 255.
- ;
- NEWTON: MOV CX,AX ;Save argument in CX.
- DIV BL ;Divide by guess.
- ADD BL,AL ;Guess + quotient.
- RCR BL,1 ;New guess=(old guess+quot)/2.
- MOV AL,BL ;RCR shifts in carry from ADD.;
- MUL AL ;If the square of the new guess
- CMP AX,CX ;is greater than the argument,
- JBE GOT_ROOT ;then we decrement new guess
- DEC BX ;to get the correct root.
- ;
- GOT_ROOT: POP CX
- POP AX
- RET
- ;
- CALC_ROOT ENDP
- ;
- ;Listing 1 - Continued.
- ;------------------------------------------------------------;
- ; Code to time and test CALC_ROOT is designed to be run under;
- ; DEBUG and does not do a normal return to DOS but instead ;
- ; does an INT 3 at the end of each routine. ;
- ;------------------------------------------------------------;
- TIME PROC FAR
- ;------------------------------------------------------------;
- ; TIME_ROOT computes the root of each of 65536 possible ;
- ; arguments 15 times for a total of 983,040 roots. ;
- ; TIME_OVER represents the looping overhead in TIME_ROOT. ;
- ; The difference between the two times is the time to call ;
- ; and execute CALC_ROOT. ;
- ;------------------------------------------------------------;
- MOV BP,15
- TIME_OVER: MOV SI,0 ;Initial value.
- INNER_OVR: MOV BX,SI
- INC SI
- JNZ INNER_OVR
- DEC BP
- JNZ TIME_OVER
- END_OVER: MOV AH,2
- MOV DL,7 ;Beep speaker.
- INT 21H
- INT 3
- ;
- MOV BP,15
- TIME_ROOT: MOV SI,0 ;Initial value.
- INNR_ROOT: MOV BX,SI
- CALL CALC_ROOT
- INC SI
- JNZ INNR_ROOT
- DEC BP
- JNZ TIME_ROOT
- END_TIME: MOV AH,2
- MOV DL,7 ;Beep speaker.
- INT 21H
- INT 3
- ;
- TIME ENDP
- ;
- ;Listing 1 - Continued.
- ;
- TEST PROC FAR
- ;------------------------------------------------------------;
- ; If CHK_ROOT detects a bad root, it displays a message and ;
- ; leaves the NG root in BX and the argument in SI. ;
- ; If all roots are OK, a message to this effect is displayed.;
- ;------------------------------------------------------------;
- MOV SI,0 ;Initial value.
- CHK_ROOT: MOV BX,SI
- CALL CALC_ROOT
- MOV AX,BX
- MUL AX ;DX,AX contains root^2.
- JO NG_ROOT ;NG if root ^2 > 65535.
- CMP AX,SI
- JA NG_ROOT ;NG if root^2 > argument.
- MOV AX,BX
- INC AX
- MUL AX ;DX,AX contains (root+1)^2.
- JO NEXT_ARG ;If ovflow then OK.
- CMP AX,SI
- JBE NG_ROOT ;NG if (root+1)^2 <=argument.
- NEXT_ARG: INC SI
- JNZ CHK_ROOT
- JMP SHORT OK_ROOTS
- ;
- OK_MSG DB 0DH,0AH,'All roots tested OK.',0DH,0AH,'$'
- NG_MSG DB 0DH,0AH,'Bad root in BX. Arg in SI.',0DH,0AH,'$'
- ;
- OK_ROOTS; MOV DX,OFFSET OK_MSG+100H ;DS points to Pgm Seg
- JMP SHORT DO_MSG ;Pref which is 100H
- NG_ROOT: MOV DX,OFFSET NG_MSG+100H ;lower than code seg.
- ;
- DO_MSG: MOV AH,9 ;Print string.
- INT 21H
- INT 3 ;Back to DEBUG.
- ;
- TEST ENDP
- ;
- INT_ROOT ENDS
- ;
- END TEST
-
-
-
-
- ;Listing 2 - BASIC program to test if a formula makes good square root guesses.
-
- 10 FOR I = 2 TO 256
- 20 Q = I*I - 1
- 30 '
- 40 'Trial Formula to Calculate P0.
- 50 '
- 60 QHI = INT(Q/256): QLO = Q-QHI*256
- 70 IF QHI = 0 THEN P0 = INT(QLO/32) + 3: GOTO 160
- 80 IF QHI < 16 THEN P0 = 13 + 4*QHI: GOTO 160
- 90 IF QHI < 128 THEN P0 = QHI + 50; GOTO 160
- 100 IF QHI = 255 THEN P1 = 255: GOTO 210
- 110 P0 = QHI + 40
- 120 IF P0 > 255 THEN P0 = 255
- 130 '
- 140 ' Newtons Method
- 150 '
- 160 P1=INT((P0 + INT(Q / P0)) / 2)
- 170 IF P1 > 255 THEN PRINT "P1 > 255 when Q = ";Q:END
- 180 '
- 190 'Test result
- 200 '
- 210 P = INT(SQR(Q))
- 220 IF P1 <= P+1 GOTO 240
- 230 PRINT "For Q = ";Q;" P1 is greater than P+1. ":END
- 240 NEXT I
- 250 PRINT "Formula works for all worst cases."
-
-
-
-
- Listing Three
-
- INCLUDE MACLIB.ASM ;by Neil R. Koozer
- LIST ON ; Kellogg Star Rt. Box 125
- MACLIST OFF ; Oakland, OR 97462
- ; (503)-459-3709
- ;SQR.ASM
-
- ;Note that words like BR1 and BFS1 are macros to emulate BR:B and BFS:B
-
- GLOBAL SQR
-
- SQR ;square root function for 32000 floating point
- RESTORE [R0] ;use ret. addr as a pointer
- MOVD 0(R0),R1 ;get operand address
- MOVD 0(R1),R6 ;get part of operand
- MOVD 4(R1),R7 ;get other part of operand
- SBITB 31,R7 ;make the implicit 1 explicit
- MOVD R6,R1 ;get exponent
- ANDW 7FFH,R1 ;clean exponent
- ADDW 3FFH,R1 ;fix offset
- ROTW -1,R1 ;div exp by 2
- CBITB 15,R1 ;test & clear wrap-around bit, 1=odd 0=even
- SAVE [R0,R1] ;save exp & ret addr
- MOVB R7,R6 ;prepare for right shift
- BFS1 SQR1 ;jump if exponent was odd
- LSHD -4,R7 ;shift -3 for safety & -1 to get halfx
- ROTD -4,R6
- ANDW FF80H,R6 ;remove non-mantissa bits
- MOVD 4C1BF828H,R3 ;y seed = 1.189.../2
- BR1 SQR2
- SQR1
- LSHD -3,R7 ;shift -3 for safety, -1 to get halfx, +1 because
- ROTD -3,R6 ; orig exp was odd
- ANDW FF00H,R6 ;remove non-mantissa bits
- MOVD 6A227E65H,R3 ;y seed = 1.68.../2
-
-
- SQR2 ;We will do 3 iterations with 32-bit precision
- MOVD R7,R5 ;get halfx into R5
- DEID R3,R4 ;R5 = halfx/y0 (the junk in R4 doesn't matter)
- LSHD -1,R3 ;R3 = y0/2
- ADDD R5,R3 ;R3 = new y0
-
- MOVD R7,R5 ;second iteration
- DEID R3,R4
- LSHD -1,R3
- ADDD R5,R3
-
- MOVD R7,R5 ;third iteration
- DEID R3,R4
- LSHD -1,R3
- ADDD R5,R3
-
-
- MOVD R6,R4 ;Now the final iteration at full precision
- MOVD R7,R5 ;get R4R5 = halfx from R6R7
-
- DEID R3,R4 ;now divide halfx (R4R5) by y (R2R3)
- MOVD R2,R0
- MEID R5,R0
- NEGD R0,R0
- SUBCD R1,R4
- MOVD R4,R1
- BCC1 DIV1
- DIV2
- ADDQD -1,R5
- ADDD R2,R0
- ADDCD R3,R1
- BCC DIV2
- DIV1
- DEID R3,R0
- MOVD R1,R4 ;R4R5 now = halfx / y
-
- MOVB R3,R2
- LSHD -1,R3
- ROTD -1,R2 ;R2R3 = y/2
-
- ADDD R4,R2
- ADDCD R5,R3 ;R2R3 = y/2 + halfx/y
- ;4th iteration complete
-
- RESTORE [R0,R1] ;get exponent & ret. addr
- ADDD R2,R2 ;shift mantissa back where it belongs
- ADDCD R3,R3
- BCC1 SQR4 ;there should almost never be a carry
- MOVB R3,R2
- LSHD -1,R3 ;undo that last shift & zero the MSbit
- ROTD -1,R2
- ADDQW 1,R1 ;adjust exponent
- BR1 SQR5 ;done
- SQR4
- CBITB 31,R3 ;test & clear MSbit (make it a + sign)
- BFS1 SQR5 ;it would virtually always be a 1
- ADDD R2,R2 ;if not, shift left again
- ADDCD R3,R3
- ADDQW -1,R1 ;adjust exponent
- CBITB 31,R3 ;make it +
- SQR5
- ANDW F800H,R2 ;clean the mantissa
- ORW R1,R2 ;append the exponent
- MOVD 4(R0),R1 ;get addr of destination variable
- MOVD R2,0(R1) ;store result in dest. variable
- MOVD R3,4(R1)
- JUMP 8(R0) ;return to caller
-
- END
-