Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
master
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
SUBTTL $FIDIG ADD TEXT DIGIT TO CURRENT ACCUMULATED NUMBER
;***************************************************************
;
; $FIDIG CONVERTS DIGIT POINTED TO BY (BX) TO BINARY
; VALUE AND ADDS TO NUMBER ACCUMULATED. AT THE
; APPROPRIATE TIMES CONVERSION WILL TAKE
; PLACE TO THE NEXT HIERARCHY OF NUMBERS,I.E.
; INTEGER-SINGLE PRECISION-DOUBLE PRECISION.
; CALLING SEQUENCE: CALL $FIDIG
; WITH (BX) POINTING TO NUMBER IN THE
; TEXT BUFFER. NUMBER IS ACCUMULATED IN THE FAC.
;
;****************************************************************
;******************************************************************
;AS $FIDIG IS ENTERED CF=1 AND (DI) WILL HOLD PLACES TO THE RIGHT OF
;DECIMAL POINT (IF DECIMAL POINT HAS OCCURRED).(CX) WILL BE EITHER
;ALL BITS SET OR ALL BITS CLEARED. ALL BITS SET INDICATES A DECIMAL
;POINT HAS NOT BEEN SEEN YET AND (CX)=0 INDICATES D. P. SEEN
;******************************************************************
$FIDIG: ADC DI,CX ;(DI) INCREMENTED ONLY IF D.P. SEEN
PUSH BX ;MUST NOW SAVE ALL NECESSARY REGS.
PUSH DI
PUSH CX
SUB AL,LOW "0" ;SUBTRACT OUT ASCII BIAS
PUSH AX ;SAVE ON STACK
CALL $GETYP ;SET CONDITION CODES
POP AX ;RECALL DIGIT
CBW ;ZERO AH
JNS FI05 ;MUST BE S.P. OR D.P. ALREADY
MOV BX,WORD PTR $FACLO ;FETCH THE INTEGER ALREADY ACCUM.
CMP BX,3277D ;IS IT ALREADY TOO BIG TO ADD
;ANOTHER DIGIT TO?
JNB FFI10 ;IF SO GO MAKE S.P. FIRST
MOV CX,BX ;SAVE ORIGINAL (BX)
SHL BX,1 ;(BX)=(BX)*2
SHL BX,1 ;(BX)=(BX)*4
ADD BX,CX ;(BX)=(BX)*5
SHL BX,1 ;(BX)=(BX)*10
ADD BX,AX ;ADD IN THE DIGIT
JS FFI10 ;IF SF=1 WE HAVE 32768 OR 32769
MOV WORD PTR $FACLO,BX ;STORE IN $FAC
JMP SHORT FI50
FI05: ;TO GET HERE NUMBER WAS ALREADY S.P. OR D.P.
PUSH AX ;SAVE THE NUMBER
JB FFFI20 ;IT'S CURRENTLY SINGLE PRECISION
JMP SHORT FI40 ;DOUBLE PRECISION
FFI10: ;TO GET HERE NUMBER WAS PREVIOUSLY AN INTEGER BUT HAS
;GROWN TOO LARGE - MUST MAKE IT SINGLE PRECISION
PUSH AX ;SAVE THE NUMBER
CALL $CSI ;CONVERT INTEGER TO S.P.
JMP SHORT FI30 ;MUL BY 10 AND ADD IN DIGIT
FFFI20: ;TO GET HERE NUMBER WAS ALREADY SINGLE PRECISION
;MUST CHECK TO SEE IF ACCURACY MIGHT BE LOST IF WE
;MULTIPLY OUR FAC BY 10,I.E. FAC MUST BE SMALLER
;THAN 1000000.
MOV WORD PTR $DBUFF+4,22000
MOV WORD PTR $DBUFF+6,112164
MOV BX,OFFSET $DBUFF+6
CALL $COMPM ;COMPARE TO $FAC
JNS FI35 ;GO DO D.P. IF TOO LARGE FOR S.P.
FI30: CALL $MUL10 ;MULTIPLY $FAC BY 10
POP DX ;RECALL DIGIT
PUSH WORD PTR $FACLO
PUSH WORD PTR $FAC-1 ;FAC PUSHED ON STACK
CALL $FLT ;CONVERT INTEGER TO S.P.
POP BX ;RECALL FAC
POP DX
CALL $FADDS ;ADD IN THE NEW DIGIT
JMP SHORT FI50 ;GET STACK RIGHT AND RETURN
FI35: ;TO GET HERE WE ALREADY HAVE 7 DIGITS AND WOULD
;HAVE A LOSS OF ACCURACY IF WE CONTINUED IN S.P. SO WE
;NEED TO CONVERT TO D.P. MULTIPLY BY 10 AND ADD IN THE DIG.
CALL $CDS ;CONVERT THE SINGLE TO D.P.
FI40: CALL $MUL10 ;MULTIPLY BY 10
CALL $MOVAF ;MOVE $FAC TO $ARG
POP DX ;RECALL DIGIT
CALL $FLT ;CONVERT TO S.P.
CALL $CDS ;CONVERT TO D.P.
CALL $FADDD ;ADD IN THE OLD ACCUMULATED VALUE
FI50: POP CX ;GET DECIMAL POINT FLAG BACK
POP DI ;GET NO. DIGITS TO RIGHT OF DECIMAL PT.
POP BX ;GET TEXT POINTER BACK
RET ;COMPLETE
SUBTTL $FINEX EXPONENT INPUT ROUTINE
;*************************************************************
;
; $FINEX THE PURPOSE OF THIS ROUTINE IS TO DETERMINE
; THE INPUT EXPONENT BASE 10 AND LEAVE IN (DX).
; ADDITIONALLY IF A MINUS "-" SIGN IS ENCOUNTERED
; $FINEX WILL SET ALL BITS OF (SI). OTHERWISE ALL
; BITS OF (SI) WILL BE CLEARED.
; CALLING SEQUENCE: CALL $FINEX
; WITH THE SIGNIFICANT DIGITS OF THE NUMBER IN
; THE FAC.
;
;***************************************************************
$FINEX: LAHF ;SAVE STATUS
CMP BYTE PTR $VALTP,LOW 10 ;SEE IF ALREADY D.P.
JNZ EXA
SAHF ;GET STACK RIGHT
JMP EXB
EXA: SAHF ;RESTORE CODES
PUSH BX ;SAVE IMPORTANT REGISTERS
PUSH DI ;PRECISION ACCORDING TO ZF. IF
CALL $FINFC ;ZF=1 S.P.:ZF=0 THEN D.P.
POP DI ;RECALL DIGITS TO RIGHT OF D.P.
POP BX ;RECALL TEXT POINTER
EXB: XOR SI,SI ;IN CASE EXPONENT IS POSITIVE
MOV DX,SI ;WILL BUILD EXPONENT IN DX
CALL $CHRGT ;GET FIRST CHARACTER OF EXPONENT
JB FX20 ;NO SIGN SO DEFAULT POS.
CMP AL,LOW "-" ;NEGATIVE EXPONENT
JNZ FX00 ;IF NOT MUST BE POSITIVE
NOT SI ;NEGATIVE EXPONENT
JMP SHORT FX10 ;GO GET NEXT CHARACTER
FX00: CMP AL,LOW "+"
JZ FX10
;ILLEGAL CHARACTER MUST LEAVE
RET ;(BX) POINTING HERE
FX10: CALL $CHRGT ;GET NEXT CHARACTER
JB FX20 ;IF DIGIT PROCESS AS EXPONENT
RET ;OTHERWISE RETURN
FX20: CMP DX,3276D ;OVERFLOW IF THIS DOESN'T GET CF=1
JB FX30 ;NO-USE THIS DIGIT
MOV DX,32767D ;TO ASSURE OVERFLOW
JMP SHORT FX10
FX30: PUSH AX ;SAVE NEW DIGIT
MOV AX,10D ;MUST MULTIPLY DX BY 10
MUL DX ;ANSWER NOW IN AX
POP DX ;RECALL DIGIT TO DX
SUB DL,LOW 60 ;SUBTRACT OUT ASCII BIAS
XOR DH,DH ;TO BE SURE AX HAS CORRECT NO.
ADD DX,AX ;ADD TO DX
JMP SHORT FX10
SUBTTL FINFC INPUT FORCE ROUTINES FOR "#","%","!"
;*********************************************************
;
; FINFC THIS MODULE CONTAINS THE ROUTINES $FINI,
; $FIND, AND $FINS FOR FORCING THE INPUT TO
; INTEGER, DOUBLE PRECISION OR SINGLE PRECISION
; RESPECTIVELY IN RESPONSE TO AN INPUT "$","#", OR
; "!". ADDITIONALLY THIS MODULE CONTAINS
; THE UTILITY ROUTINES $FI,$FS,$FD,$CSI,$CSD,$CDS
; FOR FORCING INTEGER,SINGLE,DOUBLE,CONVERTING
; INTEGER TO SINGLE,CONVERTING DOUBLE TO SINGLE, AND
; CONVERTING SINGLE TO DOUBLE, RESPECTIVELY
; CALLING SEQUENCE: CALL $FINI
; OR CALL $FIND
; OR CALL $FINS
; OR CALL $FS
; OR CALL $FD
; OR CALL $FI
; OR CALL $CSI
; OR CALL $CSD
; OR CALL $CDS
; WITH THE FAC CONTAINING THE CURRENT ACCUMULATED
; NUMBER.
;
;***********************************************************
$FIND: ;FORCE INPUT TO DOUBLE PRECISION
OR AL,LOW 1 ;TO SIGNAL DOUBLE PRECISION
$FINS: ;FORCE INPUT TO SINGLE PRECISION (caller has set Z flag)
PUSH BX ;SAVE TEXT POINTER
PUSH DI ;SAVE NO DIGITS AFTER DECIMAL POINT
JNZ FC10 ;Force to double for $FIND callers.
CALL $FS ;Force to single for $FINS callers.
JMP SHORT FC20 ;Skip over $FD call.
FC10: CALL $FD ;FORCE FAC TO DOUBLE PREC.
FC20: POP DI ;RECALL NO DIGITS TO RT. OF DEC PT
POP BX ;RECALL TEXT POINTER
XOR SI,SI ;SINCE THIS IS A FORCED
MOV DX,SI ;NO. EXPONENT IS ZERO
CALL $FINE ;DO IMPLIED EXPONENT FIX-UP
FC30: INC BX ;Point past the force character and
RET ;return.
$FINI: CALL $GETYP ;SET COND CODES ACCORDING TO TYPE
JS FC30
JMP $SNERR ;CAN'T MAKE INTEGER IF NOT ALREADY
$FINFC: JZ $FD ;IF ZF=1 THEN DOUBLE PRECISION
FRCSNG:
$FS: ;FORCE SINGLE PRECISION
CALL $GETYP ;SET COND CODES ACC. TO TYPE
JPO FC200 ;IF ALREADY S.P. RETURN
JNZ FS10
JMP $TMERR ;CAN'T FORCE A STRING
FS10:
JNS $CSD ;IF NOT INTEGER FORCE DOUBLE TO S.P.
CALL $CSI ;FORCE INTEGER TO SINGLE
JMP SHORT FC200
$CSD: ;CONVERT DOUBLE TO SINGLE PRECISION
MOV AL,LOW 4 ;SINGLE PREC DESIGNATION
MOV BYTE PTR $VALTP,AL
MOV BL,BYTE PTR $FAC-1 ;FETCH HIGH MANTISSA BITS
MOV BYTE PTR $FAC+1,BL ;MOVE SIGN TO $FAC+1
MOV DX,WORD PTR $FAC-3 ;FETCH REST OF MANTISSA
MOV AH,BYTE PTR $FAC-4 ;FETCH OVERFLOW BITS
OR AH,LOW 100 ;WANT ROUND-UP IF HIGH BIT SET
OR BL,LOW 200 ;PUT IN UNDERSTOOD 1
JMP $ROUNM ;GO ROUND THE NUMBER
FRCDBL:
$FD: ;FORCE TO DOUBLE PRECISION
CALL $GETYP ;DETERMINE CURRENT TYPE
JNB FC200 ;IF ALREADY DOUBLE EXIT
JNZ FD10
JMP $TMERR
FD10:
JNS $CDS ;IF NOT INTEGER PROCEED
CALL $CSI ;CONVERT INTEGER TO SINGLE PREC.
$CDS: MOV AL,LOW 10 ;DOUBLE PREC. INDICATOR
MOV BYTE PTR $VALTP,AL ;SET TYPE TO D.P.
XOR AX,AX ;MUST ZERO OVERFLOW BYTES
MOV WORD PTR $DFACL,AX
MOV WORD PTR $DFACL+2,AX
RET
$CSI: PUSH DX ;SAVE (DX)
PUSH SI ;SAVE (SI)
MOV DX,WORD PTR $FACLO ;FETCH THE INTEGER
CALL $FLT ;FLOAT THE INTEGER AND STORE IN FAC
POP SI ;GET REGISTERS RIGHT
POP DX
FC200: RET
FRCINT:
$FI: ;FORCE INTEGER
CALL $GETYP ;SEE WHAT WE'RE IN FOR
JNS FI10 ;IF NOT INTEGER ALREADY - JUMP
MOV BX,WORD PTR $FACLO
RET
FI10:
JNZ FFI20
JMP $TMERR ;IF STRING - ERROR
FFI20:
$CINC: ;Single precision, operand in FAC
$CIND: ;Double precision uses same routine
PUSH AX
PUSH CX
MOV AX,WORD PTR $FACM1 ;Get exponent
MOV CX,WORD PTR $FACLO ;Get mantissa
CINT:
XOR BX,BX ;Set up zero result
SUB AH,LOW 200O ;Take bias out of exponent
JB CXRET ;Return zero if no integer part
MOV BH,AL ;Highest byte of mantissa
MOV BL,CH
XCHG AX,CX
MOV CL,LOW 16D
SUB CL,CH ;Number of bits to shift mantissa right
MOV AH,BH ;Save sign
JB OVERFLOW ;If negative shift, it won't fit in 16 bits
JZ OVCHK ;Only -32768 has 16 bits - go check for it
OR BH,LOW 200O ;Set implied bit
SHR BX,CL ;Position the integer
ADC BX,0 ;Perform rounding
JO POSBOVER
OR AH,AH ;Check sign now
JNS CXRET
NEG BX
CXRET:
POP CX
POP AX
MOV WORD PTR $FACLO,BX ;Result in both FAC and BX
VALINT:
$VALNT: MOV BYTE PTR $VALTP,LOW 2
RET
POSBOVER: ;Here for either -32768 or overflow
OR AH,AH ;If signed then -32768
JS CXRET
JMP SHORT OVERFLOW
OVCHK:
;Come here if no shift is needed on the number, i.e., it requires a full
;16 bits. Only -32768 (8000H) is allowed.
CMP BX,100000O ;The 1 is sign bit (negative), not implied bit
JNZ OVERFLOW
TEST AL,LOW 200O ;Should we be rounding up?
JZ CXRET ;If so, that causes overflow
OVERFLOW:
JMP $OVERR
SUBTTL $FLT CONVERT INTEGER IN (DX) TO REAL AND STORE IN FAC
;****************************************************************
; $FLT CONVERTS THE SIGNED INTEGER IN (DX) TO A REAL
; (FLOATING POINT ) NUMBER AND STORES IT IN THE FAC
; AND SETS $VALTP=4
;*****************************************************************
$FLT: XOR BX,BX ;CLEAR HIGH MANTISSA BYTE (BL)
XOR AH,AH ;CLEAR OVERFLOW BYTE
MOV SI,OFFSET $FAC+1 ;FETCH $FAC ADDRESS TO (SI)
MOV BYTE PTR -1[SI],LOW 220 ;SET EXPONENT TO 16
MOV BYTE PTR 0[SI],LOW 0 ;SET SIGN POSITIVE
OR DX,DX ;SETS SF=1 IF NEGATIVE NO.
JNS FLT10 ;IF POSITIVE PROCEED
NEG DX ;NEED POSTIVE MAGNITUDE
MOV BYTE PTR 0[SI],LOW 200 ;SET SIGN TO NEGATIVE
FLT10: MOV BL,DH ;WILL MOVE (DX) TO (BLDH)
MOV DH,DL ;
MOV DL,BH ;SET (DL)=0
MOV BYTE PTR $VALTP,LOW 4 ;SET TYPE TO S.P.
JMP $NORMS ;GO NORMALIZE
SUBTTL $FMULD DOUBLE PRECISION MULTIPLICATION
;**************************************************************
;
; $FMULD THIS ROUTINE FORMS THE DOUBLE PRECISION PRODUCT
; ($FAC):=($FAC)*($ARG)
; THE TECHNIQUE USED IS DESCRIBED IN KNUTH, VOL II
; P.233 AND IS CALLED ALGORITHM "M"
; CALLING SEQUENCE: CALL $FMULD
; WITH THE MULTIPLIER AND MULTIPLICAND IN THE
; $FAC AND $ARG
;
;**************************************************************
DMULT:
$FMULD: ;DOUBLE PRECISION MULT., (FAC)=(FAC)*(ARG)
MOV AL,BYTE PTR $FAC ;WILL FIRST SEE IF FAC IS ZERO
OR AL,AL ;AND IF SO JUST RETURN
JZ FMD10
MOV AL,BYTE PTR $ARG ;WILL NOW SEE IF ARG IS ZERO AND
OR AL,AL ;IF SO SET FAC TO ZERO AND RETURN
JNZ FMD20 ;IF NOT ZERO PROCEED TO MULTIPLY
JMP $DZERO ;ZERO THE FAC
FMD10: RET
FMD20:
MOV BX,WORD PTR $ARG-1 ;FETCH SIGN AND EXP. TO BX
CALL $AEXPS ;ADD THE EXPONENTS
PUSH WORD PTR $FAC ;EXPONENT,SIGN
MOV WORD PTR $ARG-1,BX ;REPLACE UNPACKED MANTISSA
;PUT THE SIGN OF THE PRODUCT IN
;FAC+1
CALL $SETDB ;MOVE THE FAC TO $DBUFF SO PRODUCT
;CAN BE FORMED IN THE FAC, AND ZERO
;THE FAC AND RETURNS WITH (AX)=0
MOV SI,AX ;J
MOV WORD PTR $FAC,AX
MOV BX,OFFSET $DBUFF ;
MOV WORD PTR $ARG,AX
MOV BP,OFFSET $ARGLO ;POINT TO MULTIPLICAND BASE
M1: MOV AX,WORD PTR 0[BX+SI] ;FETCH MULTIPLIER V(J)
OR AX,AX ;SEE IF ZERO
JZ M4D ;IF ZERO W(J)=0
MOV DI,0 ;I
MOV CX,DI ;K
M4: MOV AX,WORD PTR 0[BX+SI] ;FETCH MULTIPLIER V(J)
MUL WORD PTR 0[BP+DI] ;FORM PRODUCT V(J)*U(J) IN (DXAX)
PUSH BX ;SAVE PTR. TO MULTIPLIER BASE
MOV BX,SI ;
ADD BX,DI ;I+J
ADD BX,OFFSET $DFACL-10 ;W(I+J) ADDRESS IN BX
ADD AX,WORD PTR 0[BX] ;(DXAX)=U(I)*V(J)+W(I+J)
JNB M4A
INC DX
M4A: ADD AX,CX ;T=U(I)*V(J)+W(I+J)+K
JNB M4B
INC DX
M4B: MOV WORD PTR 0[BX],AX ;W(I+J)= T MOD 2^16
MOV CX,DX ;K=INT(T/2^16)
POP BX ;RECALL PTR TO MULTIPLIER BASE
CMP DI,6 ;FINISHED INNER LOOP?
JZ M4C ;IF SO JUMP AND SET W(J)
INC DI
INC DI
JMP SHORT M4
M4C: MOV AX,CX ;(AX)=K
M4D: PUSH BX ;SAVE PTR TO MULTIPLIER BASE
MOV BX,OFFSET $DFACL
MOV WORD PTR 0[BX+SI],AX ;W(J)=K OR 0 (0 IF V(J) WERE 0)
POP BX ;RECALL PTR TO MULTIPLIER BASE
CMP SI,6 ;FINISHED OUTER LOOP?
JZ M5
INC SI
INC SI
JMP SHORT M1
M5: ;MULTIPLICATION COMPLETE AND IN FAC
MOV SI,OFFSET $DFACL-2 ;WILL NOW SET ST
STD ;WANT NON-ZERO BYTE ASAP SO PROB.
;SEEMS HIGHER OF GETTING ONE IF
;(SI) IS DECREMENTED
MOV CX,7 ;7-BYTE CHECK
M5AA: LODSB ;FETCH NEXT BYTE
OR AL,AL
LOOPZ M5AA
JZ M5AB ;DON'T NEED TO SET ST
OR BYTE PTR $DFACL-1,LOW 40 ;"OR" IN ST BIT
M5AB:
MOV AL,BYTE PTR $FAC-1 ;SEE IF WE NEED TO INC EXPONENT
OR AL,AL
POP WORD PTR $FAC ;RESTORE EXPONENT,SIGN
JS M6
MOV BX,OFFSET $DFACL-1 ;MUST SHIFT 1 BIT LEFT
MOV CX,4
M5A: RCL WORD PTR 0[BX],1
INC BX
INC BX
LOOP M5A
M5B: JMP $ROUND ;NOW ROUND
M6: INC BYTE PTR $FAC ;INCREMENT EXPONENT
JNZ M5B
JMP $OVFLS ;OVERFLOW!
SUBTTL $FMULS SINGLE PRECISION 8086 MULTIPLICATION
;**********************************************************
; $FMULS FMULS MULTIPLIES THE SINGLE PRECISION
; FLOATING POINT QUANTITIES (BXDX) AND (FAC)
; AND RETURNS THE PRODUCT IN THE (FAC). ONLY
; SEGMENT REGISTERS ARE PRESERVED.
;***********************************************************
$FMULS: ;(FAC)=(BXDX)*(FAC)
CALL $SIGNS ;ZF=1 WILL BE SET IF (FAC)=0
JZ FMS00 ;JUST RETURN IF (FAC)=0
OR BH,BH ;IF EXPONENT OF (BXDX) IS ZERO
JNZ FMS05 ;PROCEED IF NON-ZERO
FMS00: JMP $ZERO ;THE NUMBER IS ZERO.
FMS05:
CALL $AEXPS ;ADD THE S.P. EXPONENTS
;***************************************************************
;WILL NOW PROCEED TO MULTIPLY THE MANTISSAS. THE MULTIPLICATION
;WILL UTILIZE THE 16 BIT MUL INSTRUCTION AND THUS WILL TAKE
;PLACE AS PARTIAL PRODUCTS SINCE WE HAVE 24 BIT MANTISSAS TO
;MULTIPLY.
;***************************************************************
MOV CX,WORD PTR $FAC-1 ;(CH)=($FAC):(CL)=($FAC-1)
XOR CH,CH ;(CX) CONTAINS HIGH MANTISSA BITS
MOV AX,WORD PTR $FAC-3 ;(AX) CONTAINS LOW MANTISSA BITS OF FAC
MOV BH,CH ;SET (BH)=0 AS WELL
;*************************************************************
;AT THIS POINT WE HAVE THE FAC MANTISSA IN (CLAX) AND THE
;(BXDX) MANTISSA IN (BLDX). THE UNDERSTOOD LEADING MANTISSA
;BIT WAS INSTALLED BY $AEXPS AND THE SIGN OF THE PRODUCT
;WAS STORED IN FAC+1
;THE PRODUCT WILL BE FORMED IN (BXCX) BY PARTIAL PRODUCTS.
;FIRST THE NECESSARY ELEMENTS WILL BE PUSHED ON THE STACK
;THEN UTILIZED IN REVERSE ORDER(THAT'S THE BEST WAY TO
;GET THE THEM OFF THE LIFO STACK -TURKEY!)
;************************************************************
MOV SI,BX
MOV DI,CX
MOV BP,DX
PUSH CX ;HIGH FAC MANTISSA BITS
PUSH AX ;LOW FAC MANTISSA BITS
MUL DX ;32 BIT PRODUCT FORMED(ONLY NEED
MOV CX,DX ;MOST 16 SIGNIFICANT BITS)
POP AX ;LOW FAC MANTISSA BITS
MUL BX ;TIMES HIGH MANTISSA BITS OF (BLDX)
ADD CX,AX ;ADD TO PREVIOUS CALCULATION
JNB FMS10 ;IF CARRY NOT PRODUCED PROCEED
INC DX
FMS10: MOV BX,DX ;PROBABLY ONLY 8 BITS HERE
POP DX ;HIGH FAC MANTISSA BITS
MOV AX,BP ;LOW 16 MANTISSA BITS OF (BLDX)
MUL DX ;
ADD CX,AX ;ADD IN LOW ORDER BITS
JNB FMS20 ;JUMP IF CARRY NOT PRODUCED
INC DX ;
FMS20: ADD BX,DX ;CAN'T PRODUCE CARRY HERE
MOV DX,DI ;HIGH FAC MANTISSA BITS
MOV AX,SI ;HIGH FAC MANTISSA BITS
MUL DL ;(AX) HAS ENTIRE PRODUCT
ADD BX,AX ;ADD IT IN
JNB FMS30 ;IF NO CARRY PROCEED
RCR BX,1 ;MOVE EVERYTHING RIGHT
RCR CX,1 ;
INC BYTE PTR $FAC ;MUST NOW CHECK FOR OVERFLOW
JNZ FMS30 ;PROCEED IF NON-ZERO
JMP $OVFLS
FMS30: ;PRODUCT FORMED, MUST NOW GET MANTISSA IN (BLDXAH) FOR ROUNS
;PRODUCT IS CURRENTLY IN (BXCX)
OR BH,BH ;MUST BE SURE PRODUCT LEFT JUSTIFIED
JNS FMS35 ;IN (BXCX)
INC BYTE PTR $FAC ;NEED TO INCREMENT EXP.
JNZ FMS37 ;IF NOT OVERFLOW PROCEED
JMP $OVFLS ;OVERFLOW JUMP
FMS35:
RCL CX,1
RCL BX,1
FMS37:
MOV DL,CH
MOV DH,BL
MOV BL,BH
MOV AH,CL ;OVERFLOW BYTE
JMP $ROUNS ;GO ROUND
RET
SUBTTL $FOTAN ROUTINE TO PUT IN DECIMAL POINT AND LEADING ZEROS
;*****************************************************************
;
; $FOTAN THIS ROUTINE IS CALLED BY THE FREE FORMAT OUTPUT
; CODE TO OUTPUT DECIMAL POINT AND LEADING ZEROS.
; $FOTED THIS ROUTINE IS CALLED BY BOTH THE FREE FORMAT
; OUTPUT ROUTINE AND THE PRINT USING CODE TO OUTPUT
; THE DECIMAL POINT WHEN NECESSARY AND TO PUT IN
; COMMAS "," AFTER EACH THREE DIGITS IF THIS OPTION
; IS INVOKED.
; CALLING SEQUENCE: CALL $FOTAN
; CALL $FOTED
; WITH $FMTCX CONTAINING NUMBER PLACES PRIOR TO
; DECIMAL POINT(NEGATIVELY) IN UPPER BYTE AND
; NO PLACES BEFORE NEXT COMMA IN LOW BYTE
;
;*******************************************************************
$FOTAN:
DEC CH ;IF NEGATIVE THEN LEADING ZEROS
JNS FTD05 ;
MOV WORD PTR $DPADR,BX ;SAVE DECIMAL POINT COUNT
MOV BYTE PTR 0[BX],LOW "." ;MOVE IN DECIMAL POINT
FTN10: INC BX ;POINT TO NEXT OUTPUT POSITION
MOV BYTE PTR 0[BX],LOW "0" ;PUT IN LEADING ZERO
INC CH ;WILL INCREMENT CH UNTIL ZERO
JNZ FTN10 ;PUT IN LEADING ZEROS UNTIL CH ZERO
INC BX ;POINT TO NEXT BUFFER POSITION
XOR CX,CX ;ZERO OUT DECIMAL POINT AND COMMA CTS.
JMP SHORT FTD20 ;GET STACK RIGHT AND RETURN
$FOTED:
DEC CH ;SEE IF TIME FOR D.P.
FTD05: JNZ FTD10 ;IF NOT D.P. TIME SEE IF COMMA TIME
MOV BYTE PTR 0[BX],LOW "." ;PUT IN D.P.
MOV WORD PTR $DPADR,BX ;SAVE ADDR OF DECIMAL POINT
INC BX ;INCREMENT PAST D.P.
XOR CX,CX ;ZERO COUNTS & SET ZF=1
JMP SHORT FTD20 ;GET STACK RIGHT AND RETURN
FTD10: DEC CL ;IF ZERO TIME FOR COMMA
JNZ FTD20
MOV BYTE PTR 0[BX],LOW 54O ;COMMA
INC BX ;POINT TO NEXT BUFFER POSITION
MOV CL,LOW 3 ;
FTD20: MOV WORD PTR $FMTCX,CX ;UPDATE D.P.&COMMA COUNTS
RET
SUBTTL $FOTCV CONVERT FAC TO ASCII DIGITS
;************************************************************
;
; $FOTCV CONVERSION OF SINGLE OR DOUBLE PRECISION
; NUMBER TO ASCII DIGITS.IF DOUBLE PRECISION
; 10 DIGITS WILL BE CONVERTED WITH DOUBLE
; PRECISION POWER OF TEN INTEGERS, 3 DIGITS
; WITH SINGLE PRECISION POWER OF TEN INTEGERS
; AND 3 DIGITS WITH INTEGER POWERS OF TEN
; CALLING SEQUENCE: CALL $FOTCV
; WITH THE NUMBER TO BE CONVERTED HAVING PREVIOUSLY
; BEEN OPERATED ON BY $FOTNV TO BRACKET THE
; NUMBER AND HAVE ALL DIGITS IN THE INTEGER PORTION
; OF THE FAC. AND THE CORRESPONDING EXPONENT WILL
; BE SAVED ON THE STACK AND CONVERTED LATER.
;
;**************************************************************
$FOTCV: CALL $GETYP ;SET CONDITION CODES FOR VALTYP
JPO FCV40 ;IF SINGLE PRECISION GO PROCESS
PUSH CX ;SAVE DIGIT AND COMMA COUNT
PUSH BX ;SAVE BUFFR PTR.
MOV SI,OFFSET $DFACL ;WILL MOVE FAC TO ARG
MOV DI,OFFSET $ARGLO
MOV CX,4
CLD
REP MOVSW
CALL $DINT ;WILL SEE IF FAC ALREADY INTEGER
PUSH BX ;NEED TO CALL VCOMP WITH BX=ARG-1
MOV BX,OFFSET $ARG-1
CALL $VCOMP ;DO COMPARE
POP BX ;GET BUFFER POINTER BACK
MOV SI,OFFSET $ARGLO ;WILL MOVIE ARG TO FAC
MOV DI,OFFSET $DFACL
MOV CX,4
CLD
REP MOVSW
JZ FCV05 ;DON'T ADD .5 IF NO DIFF.
CALL $DADDH ;ADD .5 TO NUMBER
FCV05: MOV CL,BYTE PTR $FAC ;SHIFT COUNT IN (CL)
SUB CL,LOW 270
NEG CL ;MAKE SHIFT COUNT POSITIVE
CLC ;TO TELL DINT NOT TO NORMALIZE
CALL $FTDNT ;MAKE SURE ITS STILL INTEGER
POP BX ;RECALL BUFFER PTR.
POP CX ;RECALL DIGIT AND COMMA COUNT
MOV SI,OFFSET $FODTB ;DOUBLE PRECISION OUTPUT INTEGERS
MOV AL,LOW 9D ;9 DIGITS TO BE CONVERTED WITH D.P.
FCV10: CALL $FOTED ;SEE IF DECIMAL POINT NEEDED
PUSH AX ;SAVE DIGIT COUNT
MOV AL,LOW OFFSET "0"-1 ;WILL FORM DIGIT IN (AL)
PUSH AX
FCV20: POP AX ;RECALL DIGIT
INC AL ;INCREMENT TO NEXT DIGIT
PUSH AX ;SAVE DIGIT
CALL DSUBI ;SUBTRACT POWER OF TEN
JNB FCV20
CALL DADDI ;ADD POWER 10 BACK IN
;AND ADVANCE SI TO NEXT POWER 10
POP AX ;GET DIGIT BACK
MOV BYTE PTR 0[BX],AL ;PUT IN ASCII DIGIT
INC BX ;POINT TO NEXT BUFFER POSITION
POP AX ;GET DIGIT COUNT
DEC AL ;SEE IF 10 DIGITS FORMED
JNZ FCV10 ;IF NOT CONTINUE THE ALGORITHM
PUSH CX ;SAVE DECIMAL POINT COUNT
MOV SI,OFFSET $DFACL ;WILL MOVE INTO FAC
MOV DI,OFFSET $FACLO
MOV CX,2
CLD
REP MOVSW
POP CX ;RECALL DECIMAL POINT COUNT
JMP SHORT FCV50 ;GO DO THE REST OF THE DIGITS
FCV40:
;**************************************************************
;CODE BELOW WORKS WITH SINGLE PRECISION NUMBERS
;***************************************************************
PUSH BX ;SAVE BUFFER PTR
PUSH CX ;SAVE DIGIT AND COMMA COUNTS
CALL $PUSHF ;SAVE $FAC ON STACK
CALL $INT ;WILL SEE IF INTEGER CURRENTLY
POP DX ;RECALL FAC
POP BX
CALL $FCOMP ;COMPARE IF EQUAL DON'T ADD .5
JZ FCV45
MOV WORD PTR $FAC-1,BX ;MOVE BACK TO FAC
MOV WORD PTR $FACLO,DX
CALL $FADDH ;ADD .5 TO NUMBER
FCV45: MOV AL,LOW 1 ;FLAG TO QINT WE HAVE A POS. NO.
CALL $QINT ;GET INTEGER INTO (BLDX)
MOV WORD PTR $FAC-1,BX
MOV WORD PTR $FACLO,DX ;MOVE TO FAC
POP CX ;RECALL DIGIT AND COMMA COUNTS
POP BX ;RECALL BUFFER PTR
FCV50:
MOV AL,LOW 3 ;WILL CONVERT 3 DIGITS IN THIS CODE
MOV DX,OFFSET $FOSTB ;Print S.P. numbers with 7 digits
FCV60: CALL $FOTED ;SEE IF NEED A DECIMAL POINT OR COMMA
PUSH AX ;SAVE DIGIT COUNT
PUSH BX ;SAVE BUFFER POINTER
PUSH DX ;SAVE POWER OF TEN POINTER
CALL $MOVRF ;FETCH INTEGER
POP BP ;FETCH POWER TEN POINTER
MOV AL,LOW OFFSET "0"-1 ;WILL BUILD DIGIT IN (AL)
PUSH AX ;SAVE DIGIT
FCV70: POP AX ;RECALL DIGIT
INC AL ;GO TO NEXT DIGIT
PUSH AX
CALL $RSUBM ;SUBTRACT NO. POINTED TO BY (BP)
;FROM (BLDX)
JNB FCV70 ;CONTINUE UNTIL CF=1
;POWER TEN TABLE IN CODE SEGMENT
ADD DX,WORD PTR CS:0[BP] ;ADD WORD PORTION
ADC BL,BYTE PTR CS:2[BP]
;SINCE WE SUBTRACTED ONE TOO MANY
INC BP ;INCREMENT TO NEXT POWER OF TEN
INC BP
INC BP
CALL $MOVFR ;SAVE (BLDX) IN FAC
POP AX ;RECALL DIGIT
XCHG DX,BP ;SAVE POWER TEN PTR. IN DX
POP BX ;RECALL BUFFER POINTER
MOV BYTE PTR 0[BX],AL ;SEND OUT DIGIT
INC BX ;INCREMENT TO NEXT BUFFER POSITION
POP AX ;RECALL DIGIT COUNT
DEC AL ;SEE IF FINISHED
JNZ FCV60 ;IF NOT CONTINUE
INC DX ;NEED TO INCREMENT PAST 1ST
INC DX ;INTEGER SO THAT FOTCI WILL
MOV BP,DX ;FOTCI IS EXPECTING POINTER IN BP
MOV AH,LOW 4 ;CONVERT ONLY 4 DIGITS
JMP $FCI4
;INTEGER ARITHMETIC
DSUBI: ;SUBTRACT 7 BYTE INTEGER POINTED TO BY (SI) FROM $DFACL
PUSH CX ;FIRST SAVE CX,SI,DI
PUSH SI
MOV CX,7 ;7 BYTES
MOV DI,OFFSET $DFACL
CLC ;CF=0
CLD ;SO LODC WILL INCREMENT
DSUBI1: ;NEED NO. FROM CODE SEGMENT
LODS BYTE PTR ?CSLAB ;FETCH BYTE TO AL
SBB BYTE PTR 0[DI],AL ;SUBTRACT
INC DI
LOOP DSUBI1
POP SI
POP CX
RET
DADDI: ;ADD 7 BYTE INTEGER POINTED TO BY (SI) FROM $DFACL
PUSH CX ;SAVE CX,SI,DI
MOV CX,7
MOV DI,OFFSET $DFACL
CLC
CLD ;SO LODC WILL INCREMENT SI
DADDI1: ;WANT NO. FETCHED FROM CODE SEGMENT
LODS BYTE PTR ?CSLAB ;FETCH NEXT BYTE TO ADD
ADC BYTE PTR 0[DI],AL ;ADD IT IN
INC DI
LOOP DADDI1
POP CX
RET
SUBTTL $FOTNV BRACKET FAC SO PRINTABLE DIGITS IN INTEGER PART
;****************************************************************
;
; $FOTNV THIS ROUTINE MULTIPLIES THE FAC BY APPROPRIATE
; VALUES SO THAT THE PRINTABLE DIGITS (7 FOR SINGLE
; PRECISION, 16 FOR DOUBLE PRECISION) ARE IN THE
; INTEGER PART OF THE FAC . IT RETURNS THE COMPLEMENT-
; ING EXPONENT IN (AL).
; CALLING SEQUENCE: CALL $FOTNV
; WITH THE FAC CONTAINING THE DESIRED VALUE TO PRINT
; REGISTERS (BX) AND (CX) WILL RETAIN THEIR VALUES
;
;*****************************************************************
$FOTNV:
PUSH BX ;WON'T ALTER (BX) OR (CX)
PUSH CX
XOR DI,DI ;INITIALIZE EXPONENT
PUSH DI ;SAVE EXPONENT
FNV10: MOV BX,OFFSET $FOTB ;ADDRESS OF BRACKET CONTROL TABLE
MOV AL,BYTE PTR $FAC ;FETCH THE EXPONENT
;MUST FETCH FROM CODE SEGMENT
XLAT BYTE PTR ?CSLAB ;GET MULTIPLIER
OR AL,AL ;IF ZERO - DONE
JZ FNV20
POP DI ;RECALL EXPONENT
CBW ;CONVERT AL TO WORD
SUB DI,AX ;GET EXPONENT CORRECT
PUSH DI ;SAVE EXPONENT
MOV DX,AX ;DX:=exponent for MDPTEN.
CALL MDPTEN ;Multiply or divide by power of ten.
JMP SHORT FNV10 ;See if need to do it again.
FNV20: MOV BX,OFFSET $DP06+4 ;LOWER BOUND
CALL $MOVBS ;MOVE OUT TO "DS" AREA
CALL $COMPM ;ONE MORE MULT. POSSIBLE
;$COMPM WILL SET CF=1 IF $DP06
;IS LARGER, CF=0 FOR EQ OR GT
JNB FNV30 ;JUMP IF NOT NEEDED
CALL $MUL10 ;MULTIPLY BY TEN
POP DI ;RECALL EXPONENT
DEC DI ;ACCOUNT FOR MULTIPLY BY 10.
PUSH DI
FNV30: CALL $GETYP ;SET CONDITION CODES FOR TYPE
JB FNV40 ;done if single precision
MOV BX,OFFSET $DP09 ;MUST MULTIPLY BY 10^9
CALL $MOVAC ;MOVE 10^9 TO $ARG
CALL $FMULD ;PERFORM MULTIPLICATION
POP AX ;RECALL EXPONENT
SUB AL,LOW 11 ;SUBTRACT 9
PUSH AX ;Resave the exponent.
MOV BX,OFFSET HIDBL ;Is the number too big? (Will it
CALL $MOVBF ;overflow when $FOTCV adds .5 to it?)
CALL $DCMPM
JNA FNV40 ;No.
FNV44: CALL $DIV10 ;Yes, divide by ten and fix up the
;the decimal exponent.
POP AX ;restore the exponent
INC AL ;adjust for $DIV10
PUSH AX
FNV40: POP AX ;recall exponent
FNV50: POP CX ;restore registers
POP BX
OR AL,AL ;SET CONDITION CODES ACCORDING TO EXP
RET
;
; The largest double precision value that .5 can be added to without
; overflow occuring.
;
HIDBL: DB 375,377,3,277,311,33,16,266 ;9999999999999999.
SUBTTL $FOUT CONTROL OUTPUT CONVERSION
;***************************************************************
;
; $FOUT THIS ROUTINE PROVIDES TOP-LEVEL CONTROL OF THE
; FREE FORMAT OUTPUT FUNCTION.
; CALLING SEQUENCE: CALL $FOUT
;
;****************************************************************
S: MOV BX,OFFSET $FBUFF+1 ;FETCH BUFFER POINTER
MOV BYTE PTR 0[BX],LOW " " ;MOVE IN SPACE FOR POSSIBLE SIGN
PUSH BX ;SAVE BUFFER POINTER
CALL $SIGNS ;DETERMINE SIGN OF NUMBER
POP BX ;RECALL BUFFER POINTER
PUSHF ;SAVE FLAGS FOR LATER
JNS FO20 ;JUMP IF POSITIVE
MOV BYTE PTR 0[BX],LOW "-" ;PUT IN MINUS SGN
PUSH BX ;SAVE TEXT POINTER
CALL $VNEG ;NEGATE NO. SO WE WORK ONLY WITH
POP BX ;RECALL TEXT POINTER
OR AL,LOW 1 ;POS. NOS. AND SET ZF=0
FO20: INC BX ;POINT TO NEXT BUFFER POSITION
MOV BYTE PTR 0[BX],LOW "0" ;PUT IN ZERO IN CASE NO IS ZERO
POPF ;RECALL FLAGS
RET
FOUT:
$FOUT: ;FREE-FORMAT ENTRY POINT
CALL S ;DO SIGN FIX-UP
JNZ $FOUT2 ;IF NON-ZERO PROCEED
INC BX ;POINT TO NEXT OUTPUT BUFFER POS.
MOV BYTE PTR 0[BX],LOW 0 ;INDICATE END OF NUMBER
MOV BX,OFFSET $FBUFF+1 ;POINT (BX) TO START POSITION
RET
$FOUT2: CALL $GETYP ;GET TYPE NO.
JNS FO50 ;GO FORMAT SINGLE OR DOUBLE PREC.
MOV CX,OFFSET 7*400 ;default 7 digits prior to dp.
XOR AX,AX ;CLEAR COMMA COUNT
MOV WORD PTR $FMTAX,AX
MOV WORD PTR $FMTCX,CX
CALL $FOTCI ;CONVERT INTEGER TO ASCII
JMP $FOTZS ;DO LEADING ZERO SUPPRESSION
FO50: JMP $FOFMT ;SINGLE OR DOUBLE PREC. OUTPUT
SUBTTL $INT CONVERT PRESENT NO. TO INTEGER BY TRUNCATION
;***********************************************************
;
; $INT SINGLE PRECISION INT ROUTINE
; $DINT DOUBLE PRECISION INT ROUTINE
; $QINT CONVERT TO INT AND LEAVE IN (BLDX)
; $FTDNT FOUT ENTRY TO CONVERT TO INT AND LEAVE RT.ADJUSTED
; $SHRD SHIFT DOUBLE PRECISION MANTISSA RIGHT
;
;**********************************************************
;**********************************************************
;THE INT TECHNIQUE IS PRETTY STRAIGHT FORWARD EXCEPT
;FOR NEGATIVE NON-INTEGERS. THE RUB WITH THESE NOS. IS THAT
;IF THEY HAVE ANY FRACTIONAL BITS THE ANSWER IS TO
;BE THE NEXT LOWER VALUE INTEGER. FOR EXAMPLE : INT(-1.1) SHOULD
;RETURN -2 WHEREAS INT(1.1) SHOULD RETURN 1. THE TRICK USED TO
;EFFECT THIS IS TO SUBTRACT 1 FROM NEGATIVE NON-INTEGER MANTISSAS
;PRIOR TO SHIFTING OUT FRACTIONAL BITS THEN ADD 1 BACK TO THE
;MANTISSA ONCE FRACTIONAL BITS HAVE BEEN SHIFTED OUT. WITH THE
;FOLLOWING EXAMPLE (IN BINARY) WATCH HOW THIS TECHNIQUE WORKS:
;FIND INT(10011.011)
; (1) SINCE THIS IS A POSITIVE NO WE JUST SHIFT OUT
; THE FRACTIONAL BITS AND NORMALIZE
;FIND INT(-10011.011)
; (1) SUBTRACT ONE FROM THE MANTISSA YIELDING -10011.010
; (2) SHIFT OUT THE FRACTIONAL BITS YIELDING -10011.
; (3) ADD 1 TO MANTISSA YIELDING -10100 THE CORRECT VALUE
;FIND INT(-10011.000)
; (1) SUBTRACT ONE FROM MANTISSA YIELDING -10010.111
; (2) SHIFT OUT THE FRACTIONAL BITS YIELDING -10010.
; (3) ADD 1 TO MANTISSA YIELDING -10011. THE CORRECT VALUE
;******************************************************************
$DINT: ;DOUBLE PRECISION INT FUNCTION
MOV CL,BYTE PTR $FAC ;CL:=exponent.
SUB CL,LOW 270 ;Is there a fractional part?
JNB DNT20 ;RETURN IF NO FRACTIONAL BITS
NEG CL ;CL NOW POSITIVE
$FTDNT: PUSHF ;FOUT ENTRY POINT. THIS IS SEPARATE
;ENTRY POINT BECAUSE FOUT WISHES
;TO HAVE INTEGER RIGHT ADJUSTED
;IN THE MANTISSA BITS. WE WILL DO
;THE NECESSARY SHIFTS AND RETURN
;PRIOR TO NORMALIZATION IF CALLED
;BY FOUT (SIGNIFIED BY CF=0)
TEST BYTE PTR $FAC,LOW 377O ;Is the exponent zero?
JNE DINTNZ ;No, proceed.
POPF ;Yes, if the exponent is zero the
RET ;number is zero. Don't operate on
;the possible garbage in the mantissa.
DINTNZ: MOV BX,OFFSET $FAC-2
MOV AL,BYTE PTR 1[BX] ;FETCH SIGN BYTE
MOV BYTE PTR 3[BX],AL ;AND PUT IN $FAC+1 FOR $NORMD
OR AL,AL ;SEE IF NEGATIVE
PUSHF
OR AL,LOW 200 ;RESTORE HIDDEN 1
MOV BYTE PTR 1[BX],AL ;AND REPLACE
MOV BYTE PTR 2[BX],LOW 270 ;SET EXPONENT FOR POST SHIFT VALUE
POPF ;RECALL SF
PUSHF
JNS DNT10 ;IF POSITIVE PROCEED
;*****************************************************************
;NEGATIVE NO. MUST DO THE FANCY FOOTWORK DESCRIBED ABOVE
;*****************************************************************
CALL DINTA ;SUBTRACT 1 FROM MANTISSA BITS
DNT10: XOR CH,CH ;(CX)=SHIFT COUNT
CALL $SHRD ;DOUBLE PRECISION SHIFT RIGHT
POPF ;RECALL SF
JNS DNT15 ;IF POSITIVE PROCEED
CALL ADD1D ;ADD 1 TO MANTISSA BITS
DNT15: MOV BYTE PTR $DFACL-1,LOW 0 ;ZERO THE OVERFLOW BYTE
POPF ;SEE IF CALLED BY FOUT (CF=0)
JNB DNT20 ;IF SO JUST RETURN
JMP $NORMD ;OTHERWISE NORMALIZE
DNT20: RET
$SHRD: ;SHIFT RIGHT DOUBLE PRECISION
SHRD10: PUSH CX ;SAVE OUTER LOOP VARIABLE (BITS TO
;BE SHIFTED RIGHT)
PUSH BX ;SAVE POINTER TO HIGH BYTE TO SHIFT
CLC ;CF=0
CALL $SHDR ;SHIFT 1 BIT RIGHT
POP BX
POP CX ;GET OUTER LOOP VARIABLE
LOOP SHRD10
RET
DINTA: PUSH BX
MOV BX,OFFSET $DFACL ;BEGINNING ADDRESS FOR SUBTRACT
DINA10: SUB WORD PTR 0[BX],1 ;NEED CF SO CAN'T USE DEC
JNB DINA20
INC BX
INC BX ;CAN DO WORD SUBTRACTS SINCE HIGH BIT
;OF MANTISSA IS SET (THUS PROTECTING
;THE EXPONENT FROM THE SUBTRACT)
JMP SHORT DINA10
DINA20: POP BX
RET
ADD1D: ;ADD 1 TO DOUBLE PRECISION MANTISSA BITS
PUSH BX ;
MOV BX,OFFSET $DFACL
ADD10: INC BYTE PTR 0[BX]
JNZ ADD20
INC BX ;POINT TO NEXT BYTE THERE WAS A CARRY
JMP SHORT ADD10
ADD20: POP BX
RET
INT:
$INT: ;SINGLE PRECISION INT FUNCTION
MOV CL,BYTE PTR $FAC ;FETCH EXPONENT
SUB CL,LOW 230 ;CALCULATE SHIFT COUNT
JNB INT20 ;ALREADY INTEGER PROCEED
NEG CL ;GET POSITIVE SHIFT COUNT
;
; Note - At this point the carry is set. This will be used
; to indicate that this is not a QINT call. Also note that
; if the exponent is zero the above subtraction did set the
; carry so the check for the zero exponent case below is
; guaranteed to be executed.
;
QINTX: ; $QINTX'S ENTRY POINT
MOV DX,WORD PTR $FACLO ;FETCH LOW MANTISSA BITS
MOV BX,WORD PTR $FAC-1 ;FETCH EXP,SIGN,HIGH MANTISSA BITS
INC BH ;Is the exponent zero? (Test for zero
DEC BH ;without affecting the carry.)
JNE QINTNZ ;No, proceed.
XOR BL,BL ;Yes, put zero into BL,DX for QINT
XOR DX,DX ;rather than work with the possible
RET ;garbage in the mantissa (an exponent
;of zero means the number is zero).
QINTNZ: PUSHF ;Save carry which if clear indicates
;this is a QINT call.
OR BL,BL ;SEE IF NEGATIVE
PUSHF ;SAVE
MOV BYTE PTR $FAC+1,BL ;SAVE SIGN FOR NORMS
MOV BYTE PTR $FAC,LOW 230 ;SET EXP FOR POST SHIFT
OR BL,LOW 200 ;RESTORE HIDDEN 1
POPF
PUSHF ;SAVE SIGN
JNS INT10 ;
SUB DX,1 ;CAN'T DO A 'DEC' BECAUSE NEED CF
SBB BL,LOW 0 ;DO APPROPRIATE SUBTRACT TO HIGH BYTE
INT10: XOR CH,CH ;CX HAS LOOP COUNT
OR CL,CL ;IF SHIFT COUNT ZERO MUST JUMP OVER
JZ INT12 ;RIGHT SHIFTS
INT11: SHR BL,1 ;SHIFT RIGHT INTO CF
RCR DX,1 ;ROTATE RIGHT
LOOP INT11 ;WILL DO (CX) RIGHT SHIFTS
INT12: POPF ;RECALL SIGN OF NO.
LAHF ;STORE FLAGS TEMPORARILY
JNS INT15 ;PROCEED IF POSITIVE
INC DX
JNZ INT15
INC BL
INT15:
POPF ;CF=0 IF CALLED BY QINT
JNB INT20 ;JUST RETURN IF QINT CALL
XOR AH,AH ;CLEAR OVERFLOW BYTE
JMP $NORMS ;NORMALIZE AND RETURN
INT20: SAHF ;MUST SEE IF NEGATIVE
NGBLDX: JNS INT30 ;IF NOT PROCEED AS NORMAL
NOT DX ;COMPLEMENT DX
NOT BL ;AND BL
ADD DX,1 ;NEED CF SET IF DX OVERFLOWS
ADC BL,LOW 0 ;2's COMPLEMENT NOW FORMED
INT30: RET
QINT:
$QINT: ;DO INT(FAC) AND LEAVE IN (BLDX)
MOV CL,LOW 230
SUB CL,BYTE PTR $FAC ;GET SHIFT COUNT TO CL
CLC ;CF=0
JMP SHORT QINTX ;LEAVE RIGHT ADJUSTED
SUBTTL $LOG SINGLE PRECISION NATURAL LOG FUNCTION
;**********************************************************
;
; $LOG COMPUTE THE NATURAL LOG OF THE VALUE IN THE FAC
; CALLING SEQUENCE: CALL $LOG
; WITH INPUT ARGUMENT IN THE FAC
; MLLN2 IF THIS ENTRY POINT IS USED THE FAC WILL BE
; MULTIPLIED BY LN(2)
;
;************************************************************
LOG:
$LOG: CALL $SIGNS ;ERROR IF ($FAC).LE..0
JLE LG100
;****************************************************************
; WILL NOW PERFORM SPECIAL TEST FOR ARGUMENT OF 1.0 AND IF
; FOUND EQUAL ANSWER IS 0
;*****************************************************************
MOV DX,0 ;FETCH 1.0 TO (BXDX)
MOV BX,100400
CALL $FCOMP
JNZ LOG10 ;PROCEED IF NOT 1.0
MOV WORD PTR $FACLO,DX ;WILL ZERO $FAC AND RETURN
MOV WORD PTR $FACM1,DX
RET
LOG10:
MOV AL,BYTE PTR $FAC ;FETCH EXPONENT
SUB AL,LOW 200 ;TAKE OUT BIAS
CBW ;CONVERT BYTE TO WORD
PUSH AX ;AND SAVE
MOV BYTE PTR $FAC,LOW 200 ;ZERO THE EXPONENT
CALL $PUSHF ;SAVE ARG FOR Q(X) CALCULATION
MOV BX,OFFSET $LOGP ;NOW TO USE HART APPROX FOR P(X)
CALL $POLY
POP DX ;GET X OFF THE STACK
POP BX
CALL $PUSHF ;SAVE P(X)
CALL $MOVFR ;MOVE X TO FAC
MOV BX,OFFSET $LOGQ
CALL $POLY ;CALCULATE Q(X)
POP DX ;RECALL P(X)
POP BX
CALL $FDIVS ;CALCULATE P(X)/Q(X)
POP DX ;FETCH RAW EXPONENT
CALL $PUSHF ;SAVE FAC ON THE STACK
CALL $FLT ;FLOAT THE VALUE INTO THE $FAC
POP DX ;RECALL LOG2 VALUE
POP BX
CALL $FADDS ;ADD
MLLN2: MOV BX,100061 ;FETCH LN(2) TO (BXDX)
MOV DX,71030
JMP $FMULS ;MULTIPLY TO COMPLETE
LG100: JMP $FCERR
SUBTTL $NORMD DOUBLE PRECISION NORMALIZATION ROUTINE
;******************************************************************
;
; $NORMD NORMALIZES THE NUMBER IN $FAC+1 THRU $DFACL-1
; AND JUMPS TO $ROUND
; CALLING SEQUENCE: CALL $NORMD
; OR JMP $NORMD
; WILL RESULT IN NORMALIZATION FOLLOWED BY ROUNDING
; AND PACKING THE $FAC.
;
;*******************************************************************
$NORMD: MOV DL,LOW 71 ;MAX BITS TO SHIFT LEFT
MOV BX,OFFSET $DFACL-1
NORD5: MOV DI,OFFSET $FAC-1
MOV SI,OFFSET $FAC
JMP SHORT NORD30
NORD10:
MOV CX,4
CLC ;CF=0
NORD20: RCL WORD PTR 0[BX],1
INC BX
INC BX ;POINT TO NEXT WORD
LOOP NORD20
MOV BX,OFFSET $DFACL-1 ;POINT BACK TO END OF NUMBER
NORD25:
DEC BYTE PTR 0[SI] ;DECREMENT EXPONENT
JZ NORD40 ;DO CLEAN-UP IF UNDERFLOW
DEC DL ;SEE IF MAX BITS SHIFTED
JZ NORD40 ;IF SO TERMINATE SHIFTS
NORD30: TEST BYTE PTR 0[DI],LOW 377 ;SF=1 IF NOW NORMALIZED
JS NORD40 ;NORMALIZED
JNZ NORD10 ;MUST SHIFT BIT AT A TIME
;***************************************************************
;CAN DO AT 1 BYTE MOVE LEFT
;***************************************************************
SUB BYTE PTR 0[SI],LOW 10 ;SUBTRACT 8
JBE NORD40 ;UNDERFLOW
SUB DL,LOW 10 ;SEE IF MAX BITS SHIFTED
JBE NORD40 ;AND IF SO QUIT
MOV SI,OFFSET $FAC-2
MOV CX,7 ;7 BYTES TO MOVE
STD ;SO FOLLOWING MOVB WILL DECREMENT
;REPEAT CX TIMES (THE MOVB)
REP MOVSB ;MOVE
MOV BYTE PTR $DFACL-1,LOW 0 ;ZERO OVERFLOW
JMP SHORT NORD5 ;SEE IF MORE CASES
NORD40: JBE NORD50 ;UNDERFLOW JUMP
JMP $ROUND
NORD50:
JMP $DZERO
SUBTTL $NORMS SINGLE PRECISION NORMALIZATION ROUTINE
;************************************************************
;
; $NORMS SINGLE PRECISION NORMALIZATION ROUTINE
; $NORMS SHIFTS (BLDXAH) LEFT UNTIL THE SIGN
; BIT OF (BL)IS 1. FOR EACH LEFT SHIFT
; $NORMS WILL DECREMENT THE FAC
; ONCE THIS PROCESS IS COMPLETE, $NORMS WILL
; JUMP TO $ROUNS TO ROUND THE NUMBER AND
; PACK IT INTO THE FAC BYTES.
;
;*************************************************************
$NORMS:
MOV BH,BYTE PTR $FAC ;EXPONENT TO BH
MOV CX,4
NOR10: OR BL,BL ;SEE IF SIGN BIT SET
JS NOR20 ;IF SO NORMALIZATION COMPLETE
JNZ NOR15 ;UPPER BYTE NON-ZERO
SUB BH,LOW 10 ;CAN WE SUBTRACT 8 W/O UNDERFLOW?
JBE NOR17
MOV BL,DH
MOV DH,DL
MOV DL,AH
XOR AH,AH ;CLEAR OVERFLOW BYTE
LOOP NOR10
JZ NOR17 ;UNDERFLOW!
NOR15:
CLC ;CLEAR CARRY FLAG [CF]
RCL AH,1 ;SHIFT OVERFLOW BYTE LEFT.
RCL DX,1 ;SHIFT LOWER MANTISSA WORD LEFT
RCL BL,1 ;SHIFT HIGH MANTISSA BYTE LEFT
NOR16: DEC BH ;DECREMENT EXPONENT
JNZ NOR10 ;CONTINUE UNLESS UNDERFLOW
NOR17: JMP $ZERO ;ZERO THE FAC AND RETURN
NOR20: MOV BYTE PTR $FAC,BH ;UPDATE EXPONENT
JMP $ROUNS
SUBTTL $POLY SINGLE PRECISION POLYNOMIAL EVALUATOR
;*********************************************************
;
; $POLY EVALUATES THE POLYNOMIAL:
; P(X)=C0+C1X+C2X2+...+CNXN
; THE EVALUATION IS ACCOMPLISHED VIA HORNER'S
; RULE (SEE "THE ART OF COMPUTER PROGRAMMING"
; VOL.2 PP423, BY KNUTH)
; $POLYX PERFORMS THE EVALUATION X(P(X**2)) ON THE
; POLYNOMIAL MENTIONED ABOVE
; CALLING SEQUENCE: CALL $POLY
; OR CALL $POLYX
; WITH X STORED IN THE $FAC AND (BX)
; POINTING TO THE FOLLOWING:
; N+1
; CN
; CN-1
; .
; .
; .
; C0
;
;***********************************************************
$POLYX:
MOV DX,WORD PTR $FACLO ;FETCH LOW BYTES
MOV BP,WORD PTR $FACM1 ;AND HIGH BYTES
PUSH DX ;SAVE X ON THE STACK
PUSH BP ;
PUSH BX ;SAVE COEFFICIENT POINTER
MOV BX,BP ;(BXDX)=X
CALL $FMULS ;FORM X**2
POP BX ;RECALL COEFFICIENT POINTER
CALL $POLY ;FORM P(X**2)
POP BX ;FETCH X TO REGISTERS
POP DX
JMP $FMULS
$POLY: CLD ;9-Aug-82/MLC - Good for LODC, MOVW,
;and MOVW down to POL10.
MOV SI,BX ;SO WE CAN USE STRING MOVES
;MUST FETCH FROM THE CODE SEG
LODS BYTE PTR ?CSLAB ;FETCH NUMBER OF COEFFICIENTS
CBW ;(AH)=0
PUSH AX ;PUSH NUMBER ELEMENTS ON STACK
PUSH WORD PTR $FACM1 ;SAVE THE FAC ON THE STACK
PUSH WORD PTR $FACLO
MOV DI,OFFSET $FACLO
;WANT TO FETCH COEFF FROM
MOVS ?CSLAB,WORD PTR ?CSLAB
;FETCH FROM CODE SEGMENT
MOVS ?CSLAB,WORD PTR ?CSLAB
POL10:
POP DX ;FETCH LOW X
POP BX ;FETCH HIGH X
POP AX ;RECALL COEFFICIENT COUNTER
DEC AX ;DECREMENT
JZ POL30 ;JUMP WHEN COMPLETE
PUSH AX ;SAVE COUNTER
PUSH BX ;SAVE X ON THE STACK
PUSH DX
PUSH SI ;SAVE POINTER TO COEFFICIENTS
CALL $FMULS ;MULTIPLY BY X
POP SI ;FETCH COEFFICIENT POINTER
CLD ;9-Aug-82/MLC - Good for next two
;LODWs.
;MUST FETCH FROM CODE SEGMENT
LODS WORD PTR ?CSLAB ;FETCH LOW WORD
XCHG AX,DX
;MUST FETCH FROM CODE SEGMENT
LODS WORD PTR ?CSLAB ;FETCH HIGH WORD
XCHG AX,BX
PUSH SI ;SAVE COEFFICIENT POINTER
CALL $FADDS ;ADD IT IN
POP SI ;GET POINTER BACK
JMP SHORT POL10
POL30: ;CLEAR THE STACK
RET
SUBTTL $PUF PRINT-USING FOR FLOATING POINT NUMBERS
;**************************************************************
;
; $PUF THIS ROUTINE ACCEPTS EITHER SINGLE OR DOUBLE
; PRECISION FLOATING VALUES AND FORMATS THEM
; ACCORDING TO INPUT FORMATS. BOTH FIXED AND
; "E" TYPE FORMATS ARE PRODUCED BY THIS CODE
; CALLING SEQUENCE: CALL $PUF
; WITH FLOATING POINT VALUE IN THE FAC, (BX) POINTING
; TO THE NEXT PRINT POSITION IN THE OUTPUT BUFFER
; AND FORMAT SPECIFICATIONS IN AX, AND CX.
; $FMTAX LOADED INTO (AX) WILL CONTAIN COMMA COUNT
; IN (AH) AND THE FOLLOWING FORMAT IN (AL):
; BIT 7 =0 FREE FORMAT OUTPUT, NUMBER DICTATES
; OUTPUT FORMAT
; =1 PRINT USING OUTPUT. THE REMAINDER OF
; (AL) AND (CX) DICTATE HOW THE NUMBER IS
; TO BE PRINTED
; 6 IF =1 GROUP THE DIGITS IN THE INTEGER
; PART IN GROUPS OF THREE AND SEPARATE
; WITH COMMAS.
; 5 IF =1 FILL THE LEADING SPACES IN THE
; FIELD WITH ASTERISKS "*"
; 4 IF =1 OUTPUT THE NUMBER WITH A FLOATING
; DOLLAR SIGN "$"
; 3 IF =1 PRINT THE SIGN OF THE NUMBER WITH
; A PLUS "+" IF POSITIVE INSTEAD OF A SPC
; 2 IF =1 PRINT THE SIGN AFTER THE NUMBER
; 1 UNUSED
; 0 IF =1 PRINT THE NUMBER IN SCIENTIFIC
; NOTATION AND IGNORE BIT 6.
; IF =0 USE FIXED POINT NOTATION.
; $FMTCX WILL HAVE THE FOLLOWING FORMAT LOADED IN (CX)
; (CH) NUMBER PLACES IN FIELD TO LEFT OF DECIMAL POINT
; (DOES NOT INCLUDE THE DECIMAL POINT)
; (CL) NUMBER PLACES IN THE FIELD TO THE RIGHT OF THE
; DECIMAL POINT (INCLUDES DECIMAL POINT)
;
;****************************************************************
$PUF:
PUSH BX ;SAVE OUTPUT BUFFER POINTER
SHR AL,1 ;CF=1 IF "E" FORMAT DESIRED
JNB PUF10 ;IF FIXED PROCEED
JMP $PUFE ;GO DO IT
PUF10:
;******************************************************************
;KNOW THAT A FIXED FORMAT IS DESIRED. THE FOLLOWING ANALYSIS WILL
;BE PERFORMED: (1) SEE IF NO. IS .GE. 10^16 , AND IF SO
;GO PRINT WITH $FOUT AND INSERT A LEADING "%". (2) BRACKET THE
;PRINTABLE DIGITS IN THE INTEGER PART OF THE NUMBER WITH $FOTNV
;(3) SEE IF LEADING ZEROS ARE REQUIRED(THE POSITIONS SPECIFIED
;TO THE LEFT OF THE DECIMAL POINT ARE MORE THAN THE AVAILABLE
;DIGITS TO LEFT OF DECIMAL POINT). (4) SEE IF THE SUM OF THE DIGITS
;ON THE LEFT PLUS THOSE ON THE RIGHT ARE LESS THAN THE AVAILABLE
;DIGITS,I.E. WE HAVE MORE PRINTABLE DIGITS THAN REQUIRED. IF THIS
;IS THE CASE WE MUST SHIFT THE NUMBER RIGHT SO THAT WE CAN ROUND IT
;AT THE CORRECT POSITION. (5) PUT IN THE PRINTABLE DIGITS. (6) SEE
;IF TRAILING ZEROS ARE REQUIRED(SPECIFIED DIGITS TO THE RIGHT
;WERE IN EXCESS OF DIGITS AVAILABLE)
;********************************************************************
MOV BX,OFFSET $DP16 ;WILL FIRST SEE IF NO. TOO LARGE
CALL $MOVBF ;NO. MOVED TO DBUFF FOR COMPARISON
;(IT WAS PREVIOUSLY IN CODE SEGMENT)
CALL $VCOMP ;(FAC)-10^16(CF=1 IF OK)
JB PUF30 ;JUMP IF SMALL ENOUGH TO PROCESS
;******************************************************************
;NO. WAS TOO LARGE TO PRINT WITH FIXED FORMAT. MUST PRINT IN FREE-
;FORMAT WITH $FOUT AND INSERT A LEADING "%" TO INDICATE IT OVERFLOWED
;THE SPECIFIED PRINT FIELD
;*******************************************************************
POP BX ;RECALL PRINT BUFFER POINTER
CALL $FOUT ;PRINT IN FREE-FORMAT
DEC BX ;POINT TO POSITION 1
MOV BYTE PTR 0[BX],LOW "%" ;PUT IN OVERFLOW INDICATOR
RET ;DONE
PUF30:
;********************************************************************
;ALL WE KNOW AT THIS POINT IS THAT IT IS POSSIBLE TO PRINT THE
;NUMBER WITH A FIXED FORMAT, DO NOT KNOW THE SPECIFIED FIXED FORMAT
;IS SUFFICIENT. WHAT WE WILL DO IS FORMAT THE NUMBER IN FIXED FORMAT
;AND THEN JUMP TO $PUFXE AND LET HIM DETERMINE IF THE NUMBER WAS
;WITHIN THE SPECIFIED FORMAT.
;********************************************************************
CALL $GETYP ;DETERMINE TYPE
MOV CH,LOW 20 ;ASSUME DOUBLE PREC. (16 PRINTABLE POS)
JNB PUF40
MOV CH,LOW 7 ;7 print positions if single precision
PUF40: CALL $SIGNS ;SEE IF NO. IS ZERO
JZ PUF50 ;IF SO DON'T CALL $FOTNV
CALL $FOTNV ;BRACKET NO. SO ALL PRINTABLE DIGITS
;IN THE INTEGER PART OF THE NUMBER AND
;RETURN COMPLEMENTING EXPONENT IN (AL)
;AND SF=1 IF THIS EXPONENT IS NEG.
;(THERE ARE DIGITS TO RIGHT OF D.P)
PUF50: POP BX ;GET OUTPUT BUFFER POINTER BACK
JS PUF80 ;GO PRINT NO. WITH DIGITS TO RIGHT
;OF DECIMAL POINT
;*********************************************************************
;KNOW AT THIS POINT WE HAVE A NUMBER LESS THAN 10^16 THAT HAS NO
;PRINTABLE DIGITS TO RIGHT OF THE DECIMAL POINT. THEREFORE WE HAVE
;TO PUT IN LEADING ZEROS IF THE SPECIFIED PRINT POSITIONS TO THE LEFT
;OF THE DECIMAL POINT ARE MORE THAN THE PRINTABLE POSITIONS (CH)
;AND THE POSITIVE EXPONENT IN (AL)
;********************************************************************
MOV DL,AL ;SAVE THIS POSITIVE EXP. FOR LATER
ADD AL,CH ;THIS IS NECESSARY PRINT POSITIONS
;TO ACCOMODATE THIS NUMBER.
SUB AL,BYTE PTR $FMTCX+1 ;SUBTRACT DIGITS TO LEFT
JNS PUF60 ;NO LEADING ZEROS REQUIRED
NEG AL ;MUST MAKE (AL) POSITIVE FOR $FOTZ
CALL $FOTZ ;PUT IN (AL) LEADING ZEROS
PUF60: XOR CL,CL ;ZERO CREATED ZEROS
CALL DPCOM ;SET-UP DECIMAL POINT AND COMMA CT.
PUSH WORD PTR $FMTCX ;SAVE DECIMAL POINT INFO.
PUSH DX ;SAVE EXPONENT
CALL $FOTCV ;CONVERT THE BINARY NO. TO ASCII DIGITS
;NOTE THAT $FOTCV WILL ONLY CONVERT
;THE PRINTABLE DIGITS. IF THERE WAS A
;NON-ZERO EXPONENT AS WELL WE MUST
;INSERT SOME ZEROS PRIOR TO THE DECIMAL
;POINT. FURTHER WE MUST PAY ATTENTION
;TO OUR COMMA COUNT WHILE INSERTING
;THESE ZEROS.
POP DX ;RECALL EXPONENT
POP WORD PTR $FMTCX ;RECALL DECIMAL POINT INFO.
PUSH WORD PTR $FMTCX ;SAVE DESIRED POSITIONS LEFT/RT.
XOR AL,AL ;WANT DL IN AL WITH APPROPRIATE SIGNS
OR AL,DL ;DL=EXPONENT
JZ PUF70 ;IF NO ZEROS PRIOR TO D.P. JUMP
CALL $FOTZC ;PUT IN ZEROS AND PAY ATTENTION TO
;COMMA COUNT.
CALL $FOTED ;PUT IN DECIMAL POINT
PUF70: POP WORD PTR $FMTCX ;RECALL DESIRED POSITIONS LEFT/RT.
PUSH WORD PTR $FMTCX ;AND SAVE AGAIN
MOV AL,BYTE PTR $FMTCX ;FETCH NO. POSITIONS TO RT. OF D.P.
JMP $PUIZ ;GO PUT IN ANY REQUIRED TRAILING ZEROS
;AND CHECK TO ASSURE FIELD SPECS. MET
PUF80:
;********************************************************************
;AT THIS POINT WE KNOW WE HAVE PRINTABLE DIGITS TO THE RIGHT OF THE
;DECIMAL POINT . WE KNOW THIS BECAUSE $FOTNV WAS CALLED TO BRACKET
;THE NO. SUCH THAT THE PRINTABLE DIGITS WERE IN THE INTEGER PART
;OF THE NUMBER AND THE COMPLEMENTING EXPONENT WAS IN (AL). FURTHER
;SF=1 WAS SET TO INDICATE (AL) WAS NEGATIVE.
;WE FURTHER NEED TO DETERMINE IF WE NEED TO ROUND SOMEWHERE
;WITHIN THE PRINTABLE DIGITS. THIS WILL BE THE CASE IF THE
;DIGITS TO BE PRINTED TO THE RIGHT IS LESS THAN THOSE AVAILABLE
;TO THE RIGHT. (AL) HAS THOSE AVAILABLE TO THE RIGHT, $FMTCX HAS
;THOSE DESIRED.
;***************************************************************
MOV DL,AL ;SAVE THE COMPLEMENTING EXPONENT
MOV AL,BYTE PTR $FMTCX ;FETCH DIGITS DESIRED TO RIGHT
OR AL,AL ;IF NON-ZERO MUST SUBTRACT 1
;BECAUSE DECIMAL POINT INCLUDED
JZ PUF90 ;PROCEED IF NO DIG. TO RT. DESIRED
DEC AL ;TAKE OUT FOR DECIMAL POINT COUNT
PUF90: MOV DH,AL ;SAVE DESIRED DIGITS TO RIGHT COUNT
ADD AL,DL ;SUBTRACT DIGITS AVAILABLE TO RT.
;(THIS IS A SUBTRACT BECAUSE (DL) IS
;THE NEGATIVE TO DIGITS TO RT.)
MOV CL,AL ;WILL NEED THIS FOR LATER. IT
;IS THE NEGATIVE OF THE NUMBER
;OF DIGITS WE ARE ABOUT TO SHIFT
;OFF TO THE RIGHT
JS PUF100 ;JUMP IF INTERNAL ROUNDING NECESSARY
XOR AL,AL ;WILL NEED ALL PRINTABLE DIGITS
MOV CL,AL ;NO DIGITS SHIFTED OFF
JMP SHORT PUF110 ;DO NOT NEED TO DIVIDE IF POSITIVE
PUF100: PUSH AX
PUSH CX ;SAVE GENERATED LEADING ZEROS
PUSH DX ;
PUSH BX
CALL $DIV10 ;NEED TO ELIMINATE EXCESS PRINTABLE
POP BX
POP DX
POP CX ;RECALL GENERATED LEADING ZEROS
POP AX ;RECALL EXCESS DIGITS
INC AL ;BECAUSE AL WAS ORIGINALLY NEGATIVE
JS PUF100 ;CONTINUE FOR INTERNAL ROUNDING
MOV AH,CL ;WILL NEED CREATED LEADING ZEROS
;LATER
PUF110:
MOV AL,DL ;GET NEGATIVE EXPONENT
SUB AL,CL ;ADD CREATED ZEROS
ADD AL,CH ;IF SF=1 THEN NO DIGITS TO LEFT
JNS PUF120 ;JUMP IF DIGITS TO LEFT OF DECIMAL PT
;******************************************************************
;WE KNOW HERE THAT THE ENTIRE PRINTABLE DIGITS GO TO THE RIGHT OF
;THE DECIMAL POINT. IF DIGITS WERE REQUESTED TO THE LEFT THEN WE
;NEED TO INSERT LEADING ZEROS
;********************************************************************
MOV AL,BYTE PTR $FMTCX+1 ;DESIRED LEADING DIGITS
CALL $FOTZ ;INSERT (AL) LEADING ZEROS
MOV BYTE PTR 0[BX],LOW "." ;PUT IN DECIMAL POINT
MOV WORD PTR $DPADR,BX ;*** Save DP position for $FOTED, etc. ***
INC BX ;NEXT BUFFER POSITION
XOR CL,CL ;COMMA COUNT TO ZERO
;**********************************************************
;OK WE'VE PUT IN THE REQUIRED LEADING ZEROS PRIOR
;TO THE DECIMAL POINT. WE MAY FURTHER NEED TO PUT IN A FEW
;AFTER THE DECIMAL POINT. WE KNOW THAT THE EXPONENT IS
;GREATER IN ABSOLUTE VALUE THAN THE NO. OF PRINTABLE DIGITS.
;THE NUMBER OF LEADING ZEROS REQUIRE HERE THEN IS ABS.
;VALUE OF THE EXPONENT LESS PRINTABLE DIGITS
;**********************************************************
MOV AL,DH ;Get number of digits after decimal point
SUB AL,CH ;Subtract number that will be printed by $FOTCV
CALL $FOTZ ;PUT IN (AL) LEADING ZEROS
XOR CX,CX ;*** No longer need comma & decimal info ***
PUSH DX ;*** 8-Mar-82/ngt Fix ***
PUSH WORD PTR $FMTCX ;*** Balance number of PUSHes and POPs ***
JMP SHORT PUF140 ;GO PUT IN THE DIGITS
PUF120:
;*******************************************************************
;WE KNOW HERE THAT THERE ARE DIGITS TO THE LEFT OF THE DEC.PT.
;WE NEED TO DETERMINE IF LEADING ZEROS ARE REQUIRED. THEY WILL BE
;REQUIRED IF THE SPECIFIED DIGITS TO THE LEFT IS GREATER THAN
;THE NUMBER OF PRINTABLE DIGITS LESS THOSE TO THE RIGHT. RECALL THAT
;EARLIER WE PUT THE NUMBER OF PRINTABLE DIGITS IN (CH). DUE TO THE
;ABOVE CODE WE MAY HAVE INCREASED THE NUMBER OF DIGITS AVAILABLE TO
;THE LEFT BECAUSE WE SHIFTED THE NUMBER RIGHT BRINGING IN LEADING
;ZEROS. FOR EXAMPLE: IF WE GOT HERE WITH THE NUMBER 12.78575 $FOTNV
;WOULD HAVE 1278575. IN THE FAC AND -5 IN (AL), IF FURTHER THE INPUT
;FORMAT HAD BEEN ########.## WE WOULD HAVE SHIFTED THE NUMBER 3 DIGITS
;RIGHT FOR ROUNDING PURPOSES LEAVING 1278.575 IN THE FAC AND -3 IN
;(CL). ONCE WE GO TO $FOTCV , HE SHALL PRODUCE THE DIGITS
;00012.79 SO THE FORMULA FOR LEADING ZEROS IS:
;LEADING ZEROS=DESIRED DIGITS-[(CH)+(DL)-(CL)]
; =DESIRED DIGITS-(CH)-(DL)+(CL)
;OR AS IN THIS EXAMPLE,LEADING ZEROS=8-[7+(-5)-(-3)]=3
;*********************************************************************
MOV AL,BYTE PTR $FMTCX+1 ;FETCH DESIRED DIGITS
PUSH DX ;SAVE DIGITS TO RIGHT
PUSH WORD PTR $FMTCX ;SAVE DIGITS TO LEFT/RIGHT
SUB AL,CH ;SUBTRACT PRINTABLE DIGITS
SUB AL,DL ;ADD DIGITS TO RIGHT
ADD AL,CL ;SUBTRACT CREATED LEADING ZEROS
JS PUF130 ;IF NO LEADING ZEROS REQUIRED JUMP
CALL $FOTZ ;PUT IN REQUIRED LEADING ZEROS
PUF130: CALL DPCOM ;SET UP DECIMAL POINT AND COMMA CTS.
PUF140: PUSH WORD PTR $FMTCX ;SAVE DECIMAL POINT INFO.
CALL $FOTCV ;CONVERT FAC TO ASCII DIGITS AND
;INSERT INTO OUTPUT BUFFER. DECIMAL
;POINT AND COMMA COUNTS ARE IN
;(CH)&(CL) RESPECTIVELY
POP WORD PTR $FMTCX ;Retrieve the right and left counts.
;($FMTCX:=digits to right of decimal
;point plus one for the decimal point,
;$FMTCX+1:=digits to left of decimal
;point.)
POP AX ;RECALL DIGITS TO LEFT
POP DX ;RECALL DIGITS TO RIGHT
TEST BYTE PTR $FMTCX,LOW 377O ;Is the right side count zero?
;(This count includes the point
;point itself.)
JNZ PUF150 ;No, retain the decimal point.
;Go see if trailing zeroes are needed.
MOV BX,WORD PTR $DPADR ;Yes, get rid of the decimal point
;by backing up the pointer so the
JMP $PUFXE ;GO DO FIX-UP
PUF150:
;*****************************************************************
;WE NEED TO NOW DETERMINE IF TRAILING ZEROS ARE TO BE PRINTED
;THIS WILL BE THE CASE IF NO. DIGITS TO THE RIGHT (DL) IS LESS
;THAN THOSE REQUESTED (AL).
;****************************************************************
ADD AL,DL ;SUBTRACT DIGITS TO THE RIGHT
DEC AL ;BECAUSE DECIMAL POINT WAS INCLUDED
JS PUF160 ;GO DO FIX-UP
CALL $FOTZ ;PUT IN TRAILING ZEROS
PUF160: JMP $PUFXE ;GO DO FIX-UP
DPCOM: ;ROUTINE TO SET UP DECIMAL POINT AND COMMA COUNTS
MOV AL,CH ;FETCH PRINTABLE DIGITS
ADD AL,DL ;SUBTRACT DIGITS TO RIGHT
SUB AL,CL ;ADD CREATED ZEROS
INC AL ;FOR SIGN
MOV CH,AL
DPC10: SUB AL,LOW 3 ;SUBTRACT OUT AL MULTIPLES OF 3
JG DPC10
ADD AL,LOW 3
MOV CL,AL ;COMMA COUNT NOW SET
MOV AL,BYTE PTR $FMTAX ;FETCH FORMAT FLAGS
AND AL,LOW 100 ;SEE IF COMMAS DESIRED
JNZ DPC20
MOV CL,AL ;ZERO COMMA COUNT
DPC20: RET
SUBTTL $PUFOT PRINT USING OUTPUT ROUTINE
;***************************************************************
;
; $PUFOT THIS ROUTINE PROVIDES TOP-LEVEL CONTROL OF THE
; PRINT USING OUTPUT FUNCTION.
; CALLING SEQUENCE: CALL $PUFOT
; WITH NUMBER TO BE OUTPUT IN THE FAC AND FORMAT
; SPECIFICATIONS IN (AL), AND (CX).(AL) IS SET AS
; FOLLOWS:
; BIT 7 =0 FREE FORMAT OUTPUT, NUMBER DICTATES
; OUTPUT FORMAT
; =1 PRINT USING OUTPUT. THE REMAINDER OF
; (AL) AND (CX) DICTATE HOW THE NUMBER IS
; TO BE PRINTED
; 6 IF =1 GROUP THE DIGITS IN THE INTEGER
; PART IN GROUPS OF THREE AND SEPARATE
; WITH COMMAS.
; 5 IF =1 FILL THE LEADING SPACES IN THE
; FIELD WITH ASTERISKS "*"
; 4 IF =1 OUTPUT THE NUMBER WITH A FLOATING
; DOLLAR SIGN "$"
; 3 IF =1 PRINT THE SIGN OF THE NUMBER WITH
; A PLUS "+" IF POSITIVE INSTEAD OF A SPC
; 2 IF =1 PRINT THE SIGN AFTER THE NUMBER
; 1 UNUSED
; 0 IF =1 PRINT THE NUMBER IN SCIENTIFIC
; NOTATION AND IGNORE BIT 6.
; IF =0 USE FIXED POINT NOTATION.
; (CH) NUMBER PLACES IN FIELD TO LEFT OF DECIMAL POINT
; (DOES NOT INCLUDE THE DECIMAL POINT)
; (CL) NUMBER PLACES IN THE FIELD TO THE RIGHT OF THE
; DECIMAL POINT (INCLUDES DECIMAL POINT)
;
;****************************************************************
PUFOUT:
$PUFOT:
MOV AH,AL ;FETCH FORMAT SPECS.
TEST AH,LOW 100 ;ZF=0 IF COMMAS DESIRED
MOV AH,LOW 3 ;IF COMMAS DESIRED
JNZ PFO05 ;JUMP IF COMMAS DESIRED
XOR AH,AH ;COMMAS NOT DESIRED
PFO05: MOV WORD PTR $FMTAX,AX ;SAVE COMMA COUNT AND PFORMAT SPECS
MOV WORD PTR $FMTCX,CX ;SAVE POSITIONS TO RT./LEFT
;OF DECIMAL POINT
MOV AH,AL ;FOR TESTING
MOV BX,OFFSET $FBUFF+1 ;FETCH BUFFER POINTER
MOV BYTE PTR 0[BX],LOW " " ;MOVE IN SPACE FOR POSSIBLE SIGN
TEST AH,LOW 10 ;SEE IF "+" DESIRED
JZ PFO10 ;JUMP IF NOT
MOV BYTE PTR 0[BX],LOW "+" ;MOVE IN PLUS
PFO10: PUSH BX ;SAVE BUFFER POINTER
CALL $SIGNS ;DETERMINE SIGN OF NUMBER
POP BX ;RECALL BUFFER POINTER
JNS PFO20 ;JUMP IF POSITIVE
MOV BYTE PTR 0[BX],LOW "-" ;PUT IN MINUS SGN
PUSH BX ;SAVE BUFFER PTR.
CALL $VNEG ;NEGATE NO. SO WE WORK ONLY WITH
POP BX ;RECALL BUFFER PTR.
PFO20: INC BX ;POINT TO NEXT BUFFER POSITION
MOV BYTE PTR 0[BX],LOW "0" ;PUT IN ZERO IN CASE NO IS ZERO
CALL $GETYP ;SET COND CODES ACCORDING TO TYPE
MOV AX,WORD PTR $FMTAX ;FETCH FORMAT SPECS
MOV CX,WORD PTR $FMTCX
JS PFO40 ;IF INTEGER JUMP
JMP $PUF ;DO FLOATING POINT FORMATTING
PFO40: JMP $PUI ;PROCESS INTEGER
SUBTTL $PUI PRINT USING FOR INTEGERS
;************************************************************
;
; $PUI PRINT THE INTEGER ACCORDING TO THE FORMATS IN
; $FMTCX (NO PLACES TO LEFT/RIGHT OF DECIMAL POINT)
; $FMTAX (AH)=0 OR 3 FOR COMMA INSERTION AND (AL)
; HAS THE FOLLOWING MEANING:
; BIT 7 =0 FREE FORMAT OUTPUT, NUMBER DICTATES
; OUTPUT FORMAT
; =1 PRINT USING OUTPUT. THE REMAINDER OF
; (AL) AND (CX) DICTATE HOW THE NUMBER IS
; TO BE PRINTED
; 6 IF =1 GROUP THE DIGITS IN THE INTEGER
; PART IN GROUPS OF THREE AND SEPARATE
; WITH COMMAS.
; 5 IF =1 FILL THE LEADING SPACES IN THE
; FIELD WITH ASTERISKS "*"
; 4 IF =1 OUTPUT THE NUMBER WITH A FLOATING
; DOLLAR SIGN "$"
; 3 IF =1 PRINT THE SIGN OF THE NUMBER WITH
; A PLUS "+" IF POSITIVE INSTEAD OF A SPC
; 2 IF =1 PRINT THE SIGN AFTER THE NUMBER
; 1 UNUSED
; 0 IF =1 PRINT THE NUMBER IN SCIENTIFIC
; NOTATION AND IGNORE BIT 6.
; IF =0 USE FIXED POINT NOTATION.
; CALLING SEQUENCE: CALL $PUI
; WITH THE AFOREMENTIONED INFORMATION AVAILABLE
;
;******************************************************************
$PUI: MOV AX,WORD PTR $FMTAX ;FETCH PRINT DESCRIPTION DATA
MOV CL,AH ;$FOTCI WILL NEED COMMA INFO
;IN (CL)
MOV CH,LOW 6 ;AT MOST 6 PLACES PRIOR TO DECIMAL PT
SHR AL,1 ;SETS CF=1 IF "E" TYPE PRINT DESIRED
MOV DX,WORD PTR $FMTCX ;FETCH PLACES TO LEFT/RIGHT OF DEC. PT
JNB PI10 ;IF NOT "E" FORMAT JUMP
PUSH BX ;SAVE BUFFER POINTER
PUSH DX ;SAVE PLACES TO LEFT/RIGHT OF DEC. PT
CALL $CSI ;CONVERT THE INTEGER TO S.P.
XOR AL,AL ;MUST SET ZF=1 FOR $PUFE
POP DX ;FETCH PLACES TO LEFT /RIGHT OF D.P.
JMP $PUFE ;GO FORMAT THE SINGLE PRECISION NO.
PI10: MOV AL,DH ;FETCH PLACES TO LEFT OF D.P.
SUB AL,LOW 5 ;LET'S SEE IF LEADING ZEROS NEEDED
;*******************************************************************
;AT MOST 5 PRINT POSITIONS NEEDED FOR INTEGER (-32768,32767) SO IF
;DESIRED NO. PLACES ON LEFT IS MORE THAN 5 WE NEED TO FILL THESE
;POSITIONS WITH ASCII SPACES.
;******************************************************************
JS PI20 ;JUMP IF LESS THAN 5
CALL $FOTZ ;ZERO FILL (AL) POSITIONS
PI20: PUSH DX ;SAVE POSITIONS TO LEFT/RIGHT OF D.P.
CALL $FOTCI ;CONVERT THE INTEGER TO ASCII DIGITS
;AND INSERT DECIMAL POINT AND COMMAS
;AS DESIRED
POP AX ;RECALL NO. PLACESTO LEFT/RIGHT OF D.P.
PUSH AX ;AND SAVE AGAIN
$PUIZ: OR AL,AL ;IF 0 THEN NO DECIMAL POINT DESIRED
JNZ PI30 ;IF DESIRED PROCEED
DEC BX ;THIS WILL ELIMINATE DECIMAL POINT
PI30: DEC AL ;MAY NEED TO INSERT ZEROS TO RIGHT
;OF DECIMAL POINT.
JS PI40 ;JUMP IF NOT DESIRED
CALL $FOTZ ;PUT (AL) ASCII ZEROS IN BUFFER
MOV BYTE PTR 0[BX],LOW 0 ;RE-ESTABLISH END-OF-PRINT
PI40: POP WORD PTR $FMTCX ;MAINTAIN DIGITS LEFT/RT. OF DP.
JMP $PUFXE ;BE SURE FORMAT SPECS MET
SUBTTL $RND PSEUDO-RANDOM NUMBER GENERATOR
;******************************************************************
;
; $RND GENERATE THE NEXT RANDOM NUMBER IN THE
; SEQUENCE.
;
; CALLING SEQUENCE: CALL $RND
; WITH THE PREVIOUS RANDOM NUMBER IN $RNDX
; AND DATA ITEMS $RNDA AND $RNDC SET PROPERLY
; METHOD: LINEAR CONGRUENTIAL FROM VOL. 2 CHAPTER 3 OF
; KNUTH - THE ART OF COMPUTER PROGRAMMING.
; M=16,777,216 OR 2^24; [ A MOD 8 ]=5 AND
; [ C MOD 8 ]=3
; RND(N+1)=(RND(N)*A+C)MOD M
;
; THE DATA ITEMS A AND C CORRESPOND TO $RNDA
; AND $RNDC RESPECTIVELY AND WERE CAREFULLY
; CHOSEN TO MEET THE RECIPE IN KNUTH.
;
;**************************************************************
RND:
$RND: CALL $SIGNS ;FIND WHICH MODE REQUESTED
JZ OLDRN ;RETURN PREVIOUS NO.?
JNS RND10 ;GO DO NEW SEED
MOV AX,WORD PTR $FACLO ;FETCH NUMBER
MOV WORD PTR $RNDX,AX ;AND INITIALIZE LAST RANDOM #
MOV AL,BYTE PTR $FAC-1
MOV BYTE PTR $RNDX+2,AL ;SO SEQUENCE STARTS AGAIN
RND10: MOV AX,WORD PTR $RNDX ;FETCH LOW 16 BITS OF RNDX
MUL WORD PTR $RNDA ;MULTIPLY BY LOW BITS OF A
MOV DI,AX ;SAVE LOW 16 BITS
MOV CL,DL ;SAVE UPPER 8 BITS
MOV AL,BYTE PTR $RNDA+2 ;FETCH UPPER 8 BITS OF A
XOR AH,AH ;CLEAR UPPER AX
MUL WORD PTR $RNDX ;MULTIPLY BY LOW RNDX
ADD CL,AL ;ADD TO UPPER 8 BITS
XOR AH,AH ;CLEAR UPPER AX
MOV AL,BYTE PTR $RNDX+2 ;FETCH HIGH 8 BITS OF RNDX
MUL WORD PTR $RNDA ;MULTIPLY BY LOW 16 OF A
ADD CL,AL ;ADD IN TO UPPER 8
XOR AH,AH ;CLEAR OVERFLOW BYTE FOR NORM
MOV DX,WORD PTR $RNDC ;FETCH LOW 16 OF C
ADD DX,DI ;ADD IN LOW OF RND(N)*A
MOV BL,BYTE PTR $RNDC+2 ;FETCH HIGH OF C
ADC BL,CL ;ADD WITH CARRY HIGH RND(N)*A
MOV BYTE PTR $FAC+1,AH ;SIGN IS POSITIVE
MOV AL,LOW 200 ;SO NORM WILL PRODUCE NO.
;LESS THAN 1
MOV BYTE PTR $FAC,AL
MOV WORD PTR $RNDX,DX ;SAVE NEW RND(N+1)
MOV BYTE PTR $RNDX+2,BL
MOV AL,LOW 4 ;MUST SET VALTP TO SINGLE PREC.
MOV BYTE PTR $VALTP,AL
JMP $NORMS
NEWSD: ;DETERMINE NEW RANDOM NO. SEED
MOV BX,OFFSET $FBUFF ;WILL SUM THE FIRST 32 WDS OF
MOV CX,40 ;RAM
NEW10: ADD AX,WORD PTR 0[BX]
INC BX
INC BX
LOOP NEW10
AND AL,LOW 376 ;BE SURE BIT 0=0 SO AS TO NOT
;MATCH RND0
MOV WORD PTR $RNDX,AX
JMP SHORT RND10 ;GO PROCEED AS USUAL
OLDRN: ;RETURN THE PREVIOUS RANDOM NO.
MOV DX,WORD PTR $RNDX ;FETCH LOW 16 BITS
MOV BL,BYTE PTR $RNDX+2 ;FETCH HIGH 8 BITS
XOR AX,AX ;CLEAR OVERFLOW BYTE (AH)
MOV AL,LOW 200 ;EXPONENT OF 0
MOV BYTE PTR $FAC,AL
MOV BYTE PTR $FAC+1,AH ;POSITIVE SIGN
JMP $NORMS ;GO NORMALIZE
SUBTTL $ROUND DOUBLE PRECISION ROUND ROUTINE
;*****************************************************************
;
; $ROUND ROUND THE DOUBLE PRECISION FLOATING POINT NUMBER IN
; $FAC+1 THRU $DFACL-1.
; CALLING SEQUENCE: CALL $ROUND
; WITH NUMBER IN $FAC TO BE ROUNDED
;
;******************************************************************
$ROUND: ;DOUBLE PRECISION ROUND AND PACK
MOV BX,OFFSET $DFACL-1
ADD WORD PTR 0[BX],200 ;ADD TO HIGH BIT OV OVERFLOW BYTE
MOV CX,3 ;3 MORE BYTES TO LOOK AT POTENTIALLY
JNB RDD20 ;IF CF=0 WE ARE DONE
RDD10: INC BX
INC BX
INC WORD PTR 0[BX] ;IF THIS GETS ZF=1 THEN CARRY
JNZ RDD20 ;FINISHED WHEN ZF=0
LOOP RDD10
INC BYTE PTR $FAC ;MUST INCREMENT EXPONENT
RCR WORD PTR 0[BX],1 ;SET HIGH BYTE TO 200
RDD20:
JZ RDD30 ;OVERFLOW HOOK
TEST BYTE PTR $DFACL-1,LOW 377 ;SEE IF OVERFLOW BYTE ZERO
JNZ $ROUNX
AND BYTE PTR $DFACL,LOW 376 ;MAKE ANSWER EVEN
$ROUNX:
AND BYTE PTR $FAC-1,LOW 177 ;CLEAR SIGN BIT
MOV AL,BYTE PTR $FAC+1 ;FETCH SIGN BYTE
AND AL,LOW 200 ;CLEAR ALL BUT SIGN
OR BYTE PTR $FAC-1,AL ;AND SET SIGN APPROPRIATELY
RET
RDD30: JMP $OVFLS
SUBTTL $ROUNS INTEL 8086 ROUNDING SUBROUTINE
;***********************************************************
;
; $ROUNS SINGLE PRECISION ROUNDING SUBROUTINE
; CALLING SEQUENCE: CALL $ROUNS
; ASSUMPTIONS: (BLDXAH)WILL BE ROUNDED BY ADDING
; 128 TO (AH) . IF CF (CARRY) IS SET
; AND (AH) IS NON-ZERO AFTER THIS
; ADDITION (BLDX) WILL BE INCREMENTED
; ONCE ROUNDING IS COMPLETE, LOGIC WILL
; CONTINUE INTO PAKSP FOR PACKING THE MANTISSA
; AND SIGN INTO THE FAC.
;
;**************************************************************
$ROUNS: AND AH,LOW 340 ;CLEAR SUPERFLUOUS BITS
$ROUNM: ADD AH,LOW 200 ;ADD TO MOST SIG. BIT OF AH
JNB PAKSP ;IF NO CARRY RETURN
PUSHF ;IF ZF=1 WANT TO ROUND TO EVEN
INC DX ;IF ZF=1 MUST INCREMENT BL
JNZ TSTEVN
POPF ;KNOW RESULT WILL BE EVEN
INC BL ;IF ZF=1 MUST INCREMENT EXPONENT
JNZ PAKSP
STC ;CF=1
RCR BL,1 ;THIS WILL SET HIGH BIT OF BL
INC BYTE PTR $FAC ;IF THIS CAUSES ($FAC)=0 WE HAVE
;OVERFLOW IN ROUNDING
JNZ PAKSP
JMP $OVFLS
TSTEVN: POPF ;IF ZF=1 MUST CLEAR LOW BIT OF DL
JNZ PAKSP ;GO PACK THE FAC
AND DL,LOW 376 ;CLEAR LOW BIT
PAKSP: ;PAK SINGLE PRECISION FAC. EXPONENT IS IN FAC,SIGN IN FAC+1
;THE MANTISSA IS IN (BLDX)
MOV SI,OFFSET $FAC-3 ;LOAD ADDRESS OF $FAC IN SI
MOV WORD PTR 0[SI],DX ;MOVE LOWER MANTISSA WORD IN
INC SI ;INCREMENT TO HIGH MANTISSA BYTE
INC SI ;
MOV BH,BYTE PTR $FAC+1 ;FETCH SIGN
AND BX,100177 ;CLEAR ALL BUT SIGN IN BH SIGN IN BL
OR BL,BH ;(BL) NOW IN CORRECT FORMAT
MOV BYTE PTR 0[SI],BL ;PUT INTO FAC-1
RET
SUBTTL $SIGD CALCULATE SIGNIFICANT DIGITS FOR $FOUT
;**************************************************************
;
; $SIGD WHEN $FOUT IS DETERMINING WHETHER TO PRINT
; A NUMBER IN SCIENTIFIC NOTATION OR FIXED POINT
; IT NEEDS TO KNOW THE NUMBER OF SIGNIFICANT DIGITS
; IF THE NUMBER IS LESS THAN .01 .
; PRIOR TO CALLING $SIGD, $FOUT HAS BRACKETED THE
; SIGNIFICANT DIGITS VIA $FOUNV. THE NUMBER IN THE
; FAC WILL BE AXXXXXX OR AXXXXXXXXXXXXXXX WHERE A IS
; NON-ZERO. $SIGD'S JOB IS TO DETERMINE HOW MANY OF
; THESE X'S STARTING FROM THE RIGHT ARE ZERO
; PRIOR TO A NON-ZERO X. FOR EACH ZERO X, $SIGD WILL
; INCREMENT (CL).
; CALLING SEQUENCE: CALL $SIGD
;
;*******************************************************************
$SIGD: ;(CL)=(CL)+1 FOR EACH ZERO DIGIT STARTING FROM
;THE RIGHT . ASSUMES $FOUNV HAS PREVIOUSLY OPERATED.
MOV SI,CX ;SAVE CX
CALL $VPSHF ;PUSH EITHER 4 OR 8 BYTES OF $FAC
;ON THE STACK ACCORDING TO $VALTP
MOV CX,SI ;MUSU MAINTAIN (CL)
PUSH CX
;**************************************************************
;FIRST THING WE'LL DO IS ROUND THE FAC AND MAKE SURE WE
;STILL HAVE AN INTEGER.
;***************************************************************
;*****************************************************************
;IF WE ALREADY HAVE AN EXACT INTEGER DON'T WANT TO ADD .5 HERE
;*****************************************************************
CALL $GETYP
JB SI31 ;JUMP IF SINGLE PREC
CMP BYTE PTR $FAC,LOW 270 ;IF EQUAL OR SF=0 THEN INTEGER ALREADY
JNS SI20 ;DON'T ADD .5
JMP SHORT SI32 ;PROCESS FAC NORMALLY
SI31: CMP BYTE PTR $FAC,LOW 230 ;IF SF=0 THEN INTEGER ALREADY
JNS SI20
SI32: CALL $VADDH ;ADD .5 TO FAC
CALL $VINT ;MAKE SURE WE STILL HAVE AN INTEGER
SI20:
MOV BX,OFFSET $ZLO ;FETCH ADDRESS OF Z INTO (BX)
CALL $VMVMF ;MOVE FAC TO Z , Z=INT(FAC+.5)
POP CX ;GET (CL) BACK
SI30: PUSH CX ;SAVE CX FOR LATER
MOV DI,OFFSET $Z1LO ;GET ADDRESS OF Z1
MOV BX,OFFSET $ZLO ;GET ADDRESS OF Z
CALL $VMOVM ;Z1=Z
MOV BX,OFFSET $ZLO ;FETCH ADDRESS OF Z
CALL $VMVFM ;MOVE Z TO FAC
CALL $DIV10 ;FAC=Z/10
CALL $VINT ;FAC=INT(Z/10)
MOV BX,OFFSET $ZLO
CALL $VMVMF ;Z=INT(Z/10)
CALL $MUL10 ;FAC=INT(Z/10)*10
MOV BX,OFFSET $Z1-1 ;ADDRESS OF Z1-1
CALL $GETYP ;NEED TO DECREMENT BX IF S.P.
JNB SI35
SUB BX,4 ;NOW (BX) POINTS TO S.P.
SI35:
CALL $VCMPM ;COMPARE TO FAC
POP CX ;GET SIGNIFICANT DIGIT COUNT BACK
JNZ SI40 ;THROUGH WHEN NON-ZERO
INC CL ;(CL)=(CL)+1
JMP SHORT SI30 ;LET'S GO SEE IF WE CAN FIND ANOTHER
SI40: MOV BP,CX ;SAVE CX
CALL $VPOPF ;RESTORE ORIGINAL FAC
MOV CX,BP ;RESTORE CX
RET
CSEG ENDS
END ;END MATH86.MAC