.TITLE NSIG .IDENT /V01.03/ ; ; NSIG(X[,IEXP]) -- Number of significant digits in F_FLOAT number X ; ; If second argument IEXP is specified, it receives the decimal ; exponent generated when X is printed in Ex.y format. NOTE: this is ; returned as a word (INTEGER*2) quantity!!! ; ; This allows determination of a suitable F format, as follows: ; nsig-iexp = number of digits to right of decimal point ; max(0,iexp) = number of digits to left of decimal point ; ; sample code: ; INTEGER*2 W,D,N,E ; REAL*4 X ; ... ; N=NSIG(X,E) ; D=N-E ; W=1+MAX(0,E)+1+D ! sign+left digits+point+right digits ; TYPE 1,X ; 1 FORMAT(' X = ',F.) ; ; Impure data area ; .PSECT $LOCAL,PIC,CON,REL,LCL,NOSHR,NOEXE,RD,WRT,LONG MINRES: .BLKL 1 XCMP: .BLKL 1 .LONG 0 XVAL: .BLKL 1 .LONG 0 CXCMP: .BLKB 15 CXVAL: .BLKB 15 ; ; Descriptors for strings ; .PSECT $PDATA,PIC,CON,REL,LCL,SHR,NOEXE,RD,NOWRT,LONG DXCMP: .LONG ^X010E000F .ADDRESS CXCMP DXVAL: .LONG ^X010E000F .ADDRESS CXVAL AXCMP: .LONG 3 .ADDRESS XCMP .ADDRESS DXCMP .LONG 8 AXVAL: .LONG 3 .ADDRESS XVAL .ADDRESS DXVAL .LONG 8 ; ; The real code follows ; .PSECT $CODE,PIC,CON,REL,LCL,SHR,EXE,RD,NOWRT,LONG ; ; Single entry point NSIG, takes one argument ; .ENTRY NSIG,^M MOVL #7,MINRES ; Set minimum result BICL3 #^X8000,@4(AP),-(SP) ; Get absolute value of X MOVW (SP),R0 ; Swap halves of X MOVW 2(SP),(SP) ; MOVW R0,2(SP) ; SUBL3 #1,(SP),R6 ; Get predecessor of X in R6 CMPL R6,#^X800000 ; Is it effectively zero? BGEQ 1$ ; Nope CLRL R6 ; Yes, make it really zero. 1$: CMPL (SP),#^X7FFFFFFF ; Is X largest number? BNEQ 2$ ; Nope MNEGL #1,(SP) ; Yes, make X successor 0 as a flag 2$: INCL (SP) ; Get X successor MOVW (SP),R0 ; Swap halves back again MOVW 2(SP),(SP) ; MOVW R0,2(SP) ; MOVL (SP),R7 ; Save X successor in R7 MOVL R6,(SP) ; Swap back halves of X predecessor MOVW (SP),R0 ; MOVW 2(SP),(SP) ; MOVW R0,2(SP) ; MOVF (SP),XCMP ; Copy X predecessor to location CALLG AXCMP,G^OTS$CNVOUT ; Convert X predecessor BCS 48$ ; If error, leave MOVF @4(AP),XVAL ; Get X value CALLG AXVAL,G^OTS$CNVOUT ; Convert X value BCS 48$ ; If error, leave CMPC3 #7,CXCMP+3,CXVAL+3 ; Compare predecessor and X BEQL 25$ ; If same 7 digits, NSIG is 8 or 9 22$: TSTL R7 ; Doing successor at all? BEQL 5$ ; No, NSIG must be 7 (or minimum) then MOVL R7,XCMP ; Store X successor CALLG AXCMP,G^OTS$CNVOUT ; Convert X successor BCS 48$ ; If error, leave CMPC3 #7,CXVAL+3,CXCMP+3 ; Compare successor and X BNEQ 5$ ; If different, NSIG is 7 or minimum CMPB CXVAL+10,CXCMP+10 ; Compare 8th digits BEQL 3$ ; If same 8 digits, NSIG is 9 BRB 4$ ; Else it's 8 25$: CMPB CXCMP+10,CXVAL+10 ; Compare 8th digits BEQL 3$ ; If same 8 digits, NSIG is 9 MOVL #8,MINRES ; Indicate minimum result is 8... BRB 22$ ; ...and check successor 3$: MOVL #9,R0 ; Result is 9 BRB 6$ ; Check on optional argument 4$: MOVL #8,R0 ; Result is 8 BRB 6$ ; Check on optional argument 48$: CLRL R0 ; Result is error BRB 9$ ; Go return 5$: MOVL MINRES,R0 ; Result is 7 or minimum 6$: CMPL #1,(AP) ; More than one argument? BGEQ 9$ ; No, just return result MOVAB CXVAL+12,R7 ; Get address of exponent (snn) MOVZBL 1(R7),R6 ; Get tens digit SUBB2 #^X30,R6 ; Get it in binary MULB2 #10,R6 ; Multiply by power of ten ADDB2 2(R7),R6 ; Add in other digit SUBB2 #^X30,R6 ; Subtract ASCII bias here too CMPB #^X2B,(R7) ; Was it a positive exponent? BEQL 7$ ; Yes, return as-is MNEGW R6,@8(AP) ; Negate result RET ; Return 7$: MOVW R6,@8(AP) ; Move result RET ; Return 8$: CLRL R0 ; Result is error 9$: RET ; Return .END