home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
ddjmag
/
ddj8607.arc
/
LETTERS.JUL
< prev
next >
Wrap
Text File
|
1986-07-31
|
8KB
|
284 lines
;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