%RANGECHECKS=NO %CHARCODE=EBCDIC %DIAGLINEMAP=NO %DIAGNAMETABLE=NO PROGRAM ICL9LPREALIO ; CONST MINDECIMALEXPONENT = -79 ; MAXDECIMALEXPONENT = 76 ; MAXNOOFDIGITS = 17 ; MINBINARYEXPONENT = -259 ; MAXBINARYEXPONENT = 252 ; MAXSIGFIGS = 16 ; MAXTENPOWER = 75 ; REALLENGTH = 63 ; TYPE ONEORTWO = 1 .. 2 ; DIGITSINDEX = 0 .. MAXNOOFDIGITS ; DIGITSARRAY = ARRAY [ DIGITSINDEX ] OF 0 .. 9 ; DECIMALEXPONENTRANGE = MINDECIMALEXPONENT .. MAXDECIMALEXPONENT ; BINEXPONENTRANGE = MINBINARYEXPONENT .. MAXBINARYEXPONENT ; POSITIVEDECIMALEXPONENT = 0 .. MAXTENPOWER ; SIGFIGSRANGE = 0 .. MAXSIGFIGS ; CHARACTERSET = RECORD SPACE,ZERO,PLUS,MINUS,POINT,E,LITTLEE,COMMA,ERRORCHAR : CHAR END ; REALBIT = 0 .. REALLENGTH ; BITSTRING = SET OF REALBIT ; ERRORTYPE = ( NONDIGIT , TOOLARGE , ENDOFFILE ) ; FUNCTION BITSTOREAL ( BITS : BITSTRING ) : REAL ; VAR FIDDLE : RECORD CASE TAG : ONEORTWO OF 1: (BITSIN : BITSTRING) ; 2: (REALOUT : REAL) END ; I : REALBIT ; BEGIN WITH FIDDLE DO BEGIN BITSIN := [] ; FOR I := 0 TO REALLENGTH DO IF I IN BITS THEN BITSIN := BITSIN + [ REALLENGTH - I ] ; BITSTOREAL := REALOUT ; END ; END (* BITSTOREAL *) ; FUNCTION MAX ( X,Y : INTEGER ) : INTEGER ; BEGIN IF X > Y THEN MAX := X ELSE MAX := Y ; END ; FUNCTION MIN ( X,Y : INTEGER ) : INTEGER ; BEGIN IF X < Y THEN MIN := X ELSE MIN := Y ; END ; FUNCTION TENTOTHE ( POWER : POSITIVEDECIMALEXPONENT ) : REAL ; VAR RESULT : REAL ; I : INTEGER ; BEGIN I := 0 ; RESULT := 1 ; WHILE POWER > 0 DO BEGIN IF ODD ( POWER ) THEN CASE I OF 0: RESULT := RESULT * 1E1 ; 1: RESULT := RESULT * 1E2 ; 2: RESULT := RESULT * 1E4 ; 3: RESULT := RESULT * 1E8 ; 4: RESULT := RESULT * 1E16 ; 5: RESULT := RESULT * 1E32 ; 6: RESULT := RESULT * 1E32 * 1E32 ; END ; POWER := POWER DIV 2 ; I:= I + 1 ; END ; TENTOTHE := RESULT ; END (* TENTOTHE *) ; PROCEDURE ICL9LPREADRERR(WHATSWRONG : ERRORTYPE ; VAR F : TEXT ) ; EXTERN ; (* OUTPUTS A SUITABLE ERROR MESSAGE *) (*#E+ %KEYEDENTRY ON *) PROCEDURE ICL9LPRIOREAD(VAR X : REAL ; VAR BASICCHARS : CHARACTERSET ; VAR F : TEXT ) ; (* READS A REAL NUMBER FROM THE TEXT FILE F AND LEAVES THE VALUE IN X. THE EXTERNAL NUMBER MUST APPEAR AS A VALID PASCAL CONSTANT (REAL OR INTEGER) OPTIONALLY PRECEDED BY SPACES AND END-OF-LINES. THE NUMBER IS TERMINATED BY THE FIRST INVALID CHARACTER AND F^ IS LEFT AT THAT CHARACTER. POSSIBLE ERRORS ARE TOO LARGE: THE NUMBER IS TOO LARGE TO BE STORED. INVALID CHARACTER: AN INVALID CHARACTER HAS BEEN FOUND BEFORE THE END OF THE NUMBER. NUMBERS TOO SMALL TO BE STORED (E.G. 1E-80) WILL CAUSE UNDERFLOW (ASSUMED TO BE MASKED) AND TRUE ZERO IS STORED. IF CONTROL RETURNS TO THE USER'S PROGRAM AFTER AN ERROR THE VALUE OF X IS UNDEFINED. *) LABEL 1 ; CONST MAXEXPONENT = 75 ; (* MAX E SUCH THAT TENTOTHE(E) DOES NOT OVERFLOW *) EXPLIMIT = 1000 ; (* SOME REASONABLY LARGE VALUE > MAXEXPONENT + MAXIMUM NUMBER OF SIG FIGS ( 17 FOR 2900 AND < MAXINT DIV 10 ( IT IS USED TO STOP EXPONENT OVERFLOW) *) (* THE FOLLOWING SHOULD BE CONSTANTS BUT HAVE TO BE FRIGGED AS VARIABLES MAXREAL = HEX 7FFFFFFFFFFFFFFF ( LARGEST POSITIVE REAL ) MANTISSALIMIT = HEX 4EFFFFFFFFFFFFFF ( LARGEST POSITIVE INTEGER THAT CAN BE STORED EXACTLY AS A REAL ) *) TYPE SIGNVALUE = -1 .. +1 ; VAR CH : CHAR ; EXPONENT,INTEXPONENT : INTEGER ; MAXREAL,MANTISSALIMIT,SCALEFACTOR,INTPART : REAL ; SIGN , EXPSIGN : SIGNVALUE ; NINE : CHAR ; ZEROFRACTION,ERRORFOUND : BOOLEAN ; PROCEDURE GETSIGN ( VAR SIGN :SIGNVALUE ) ; BEGIN WITH BASICCHARS DO BEGIN CH := F^ ; IF CH = MINUS THEN BEGIN SIGN := -1 ; GET(F) ; CH := F^ ; END ELSE BEGIN SIGN := +1 ; IF CH = PLUS THEN BEGIN GET(F) ; CH := F^ ; END ; END ; END ; END (* GETSIGN *) ; PROCEDURE ERROR ( WHATSWRONG : ERRORTYPE ) ; BEGIN CASE WHATSWRONG OF NONDIGIT : ICL9LPREADRERR( NONDIGIT , F ) ; TOOLARGE : ICL9LPREADRERR( TOOLARGE , F ) ; ENDOFFILE : GET(F) END ; ERRORFOUND := TRUE ; END (* ERROR *) ; BEGIN (* ICL9LPRIOREAD *) WITH BASICCHARS DO BEGIN ERRORFOUND := FALSE ; NINE := CHR( ORD( ZERO ) + 9 ) ; MAXREAL := BITSTOREAL( [ 1 .. 63 ] ) ; MANTISSALIMIT := BITSTOREAL( [ 1 , 4..6 , 8..63 ] ) ; WHILE NOT EOF(F) AND ( F^ = SPACE ) DO GET(F) ; IF EOF(F) THEN BEGIN ERROR( ENDOFFILE ) ; GOTO 1 ; END ; GETSIGN( SIGN ) ; (* GET INTEGER PART *) IF ( CHNINE ) THEN BEGIN ERROR( NONDIGIT ) ; GOTO 1 ; END ELSE BEGIN X := 0 ; EXPONENT := 0 ; REPEAT IF X < MANTISSALIMIT THEN X := 10*X + ( ORD(CH) - ORD(ZERO) ) ELSE EXPONENT := EXPONENT + 1 ; GET(F) ; CH := F^ ; UNTIL ( CH < ZERO ) OR ( CH > NINE ) ; INTPART := X ; INTEXPONENT := EXPONENT ; ZEROFRACTION := TRUE ; IF CH = POINT THEN (* GET FRACTIONAL PART *) BEGIN GET(F) ; CH := F^ ; IF ( CHNINE ) THEN BEGIN ERROR( NONDIGIT ) ; GOTO 1 ; END ELSE REPEAT IF X < MANTISSALIMIT THEN BEGIN X := 10*X + ( ORD(CH) - ORD(ZERO) ) ; EXPONENT := EXPONENT - 1 ; ZEROFRACTION := ZEROFRACTION AND ( CH=ZERO ) ; END ; GET(F) ; CH := F^ ; UNTIL ( CH < ZERO ) OR ( CH > NINE ) ; END (* FRACTIONAL PART *) ; IF ZEROFRACTION THEN X := INTPART ELSE INTEXPONENT := EXPONENT ; EXPONENT := 0 ; IF (CH=E) OR (CH=LITTLEE) THEN (* GET EXPONENT *) BEGIN GET(F) ; GETSIGN( EXPSIGN ) ; IF ( CHNINE ) THEN BEGIN ERROR( NONDIGIT ) ; GOTO 1 ; END ELSE REPEAT IF ABS(EXPONENT) < EXPLIMIT THEN EXPONENT := 10*EXPONENT + EXPSIGN * ( ORD(CH) - ORD(ZERO) ) ; GET(F) ; CH := F^ ; UNTIL ( CH < ZERO ) OR ( CH > NINE ) ; END (* GET EXPONENT *) ; EXPONENT := EXPONENT + INTEXPONENT ; IF X > 0 THEN IF EXPONENT >= 0 THEN IF EXPONENT > MAXEXPONENT THEN BEGIN ERROR( TOOLARGE ) ; GOTO 1 ; END ELSE BEGIN SCALEFACTOR := TENTOTHE( EXPONENT ) ; IF SCALEFACTOR > MAXREAL / X THEN BEGIN ERROR( TOOLARGE ) ; GOTO 1 ; END ELSE X := X * SCALEFACTOR * SIGN ; END ELSE BEGIN EXPONENT := -EXPONENT ; WHILE EXPONENT > MAXEXPONENT DO BEGIN X := X / TENTOTHE( MAXEXPONENT ) ; EXPONENT := EXPONENT - MAXEXPONENT ; END ; X := SIGN * X / TENTOTHE( EXPONENT ) ; END ; END ; 1 : END ; END (* ICL9LPRIOREAD *) ; (*#E- %KEYEDENTRY OFF *) PROCEDURE ROUNDTONSIGFIGS ( VAR DIGITS : DIGITSARRAY ; VAR DECEXPONENT : DECIMALEXPONENTRANGE ; NOOFSIGFIGS : SIGFIGSRANGE ) ; VAR CARRY : BOOLEAN ; I : SIGFIGSRANGE ; BEGIN CARRY := DIGITS[NOOFSIGFIGS + 1] >= 5 ; I := NOOFSIGFIGS ; WHILE CARRY AND ( I >= 1 ) DO BEGIN DIGITS[I] := ( DIGITS[I] + 1 ) MOD 10 ; CARRY := DIGITS[I] = 0 ; I := I -1 ; END ; IF CARRY THEN BEGIN FOR I := NOOFSIGFIGS DOWNTO 1 DO DIGITS [ I + 1 ] := DIGITS [I] ; DIGITS [ 1 ] := 1 ; DECEXPONENT := DECEXPONENT + 1 ; END ; END (* ROUNDTONSIGFIGS *) ; PROCEDURE SPLITUPREAL ( X : REAL ; VAR DIGITS : DIGITSARRAY ; VAR DECEXPONENT : DECIMALEXPONENTRANGE ; VAR POSITIV : BOOLEAN ) ; VAR MANTISSA : REAL ; BINEXP : BINEXPONENTRANGE ; FUNCTION BINARYEXPONENTOF ( X : REAL ) : BINEXPONENTRANGE ; VAR RESULT : BINEXPONENTRANGE ; BEGIN X := ABS( X ) ; RESULT := 0 ; IF X > 0 THEN BEGIN WHILE X >= 1 DO BEGIN X := X/16 ; RESULT := RESULT + 4 ; END ; WHILE X < 1/16 DO BEGIN X := X*16 ; RESULT := RESULT - 4 ; END ; WHILE X < 1/2 DO BEGIN X := X * 2 ; RESULT := RESULT - 1 ; END ; BINARYEXPONENTOF := RESULT ; END ELSE BINARYEXPONENTOF := 0 ; END (* BINARYEXPONENTOF *) ; PROCEDURE BINTODEC( MANTISSA : REAL ; VAR DIGITS : DIGITSARRAY ) ; (* ASSUMES THAT 0.1 <= MANTISSA < 1 *) CONST POWEROF16 = 65536 ; (* 16 TO THE N WHERE N >= 2 AND N<= HEX MANTISSA LENGTH -2 *) (* AND 16^N < MAXINT *) (* I.E. 2 <= N <= 7 FOR THE 2970 *) VAR TOP , BOTTOM : REAL ; TRUNCTOP , TRUNCBOTTOM : INTEGER ; LENGTH : DIGITSINDEX ; BEGIN TOP := TRUNC(MANTISSA * POWEROF16 ) / POWEROF16 ; BOTTOM := (MANTISSA - TOP) * POWEROF16 ; FOR LENGTH := 1 TO MAXNOOFDIGITS DO BEGIN BOTTOM := 10 * BOTTOM ; IF BOTTOM < 1 THEN TRUNCBOTTOM := 0 ELSE TRUNCBOTTOM := TRUNC( BOTTOM ) ; TOP := 10 * TOP + TRUNCBOTTOM / POWEROF16 ; BOTTOM := BOTTOM - TRUNCBOTTOM ; IF TOP < 1 THEN TRUNCTOP := 0 ELSE TRUNCTOP := TRUNC( TOP ) ; DIGITS[ LENGTH ] := TRUNCTOP ; TOP := TOP - TRUNCTOP ; END ; END (* BINTODEC *) ; BEGIN (* SPLITUPREAL *) IF X <> 0 THEN BEGIN IF X >= 0 THEN POSITIV := TRUE ELSE BEGIN POSITIV := FALSE ; X := -X ; END ; BINEXP := BINARYEXPONENTOF( X ) ; IF BINEXP > 0 THEN BEGIN DECEXPONENT := ( BINEXP -1 ) * 77 DIV 256 + 1 ; DECEXPONENT := MIN( DECEXPONENT , MAXTENPOWER ) ; MANTISSA := X / TENTOTHE( DECEXPONENT ) ; WHILE MANTISSA >= 1 DO BEGIN MANTISSA := MANTISSA / 10 ; DECEXPONENT := DECEXPONENT +1 ; END ; END ELSE BEGIN DECEXPONENT := BINEXP * 77 DIV 256 ; DECEXPONENT := -MIN( -DECEXPONENT , MAXTENPOWER ) ; MANTISSA := X * TENTOTHE( -DECEXPONENT ) ; WHILE MANTISSA < 1/10 DO BEGIN MANTISSA := 10 * MANTISSA ; DECEXPONENT := DECEXPONENT - 1 ; END ; END ; (* 0.1 <= MANTISSA < 1 : X = MANTISSA * TENTOTHE(DECEXPONENT) *) BINTODEC( MANTISSA , DIGITS ) ; END ELSE BEGIN DECEXPONENT := 0 ; POSITIV := TRUE ; BINTODEC( 0 , DIGITS ) ; END ; END (* SPLITUPREAL *) ; (*#E+ %KEYEDENTRY ON *) PROCEDURE ICL9LPRIOWRFIX(VALUETOBEWRITTEN : REAL ; WIDTH : INTEGER ; DECIMALPLACES : INTEGER ; VAR BASICCHARS : CHARACTERSET ; VAR F : TEXT ) ; (* WRITE A REAL NUMBER TO A TEXT FILE IN FIXED POINT FORMAT USING AT LEAST WIDTH CHARACTERS. NOT MORE THAN 16 SIGNIFICANT DIGITS ARE PRINTED AND THE NUMBER IS CORRECTLY ROUNDED TO THE NUMBER OF FIGURES SHOWN IF DECIMALPLACES <= 0 THE NUMBER IS PRINTED AS AN INTEGER (I.E. NO DECIMAL POINT) DD...D IF DECIMAL PLACES > 0 THE NUMBER IS PRINTED WITH THE REQUESTED NUMBER OF DIGITS AFTER THE DECIMAL POINT DD...DDD...D THE NUMBER IS ALWAYS PRINTED AS DEFINED BY THE VALUE OF DECIMALPLACES. IF WIDTH IS TOO LARGE THE NUMBER IS PADDED ON THE LEFT WITH SPACES. IF WIDTH IS TOO SMALL OR DECIMALPLACES < 0 THE NUMBER IS PRECEDED BY AN ASTERISK. *) (* THE POSITIONS OF CHARACTERS ARE COUNTED FROM 'START' DOWN THRO ZERO ( 1ST DIGIT AFTER '.' ) TO 'FINISH' ( <= 1 ) *) VAR I , START , SIGNPOSITION , LASTLEADINGZERO , FIRSTSIGDIGIT , LASTSIGDIGIT , FINISH : INTEGER ; DIGITS : DIGITSARRAY ; DECEXPONENT : DECIMALEXPONENTRANGE ; POSITIVE : BOOLEAN ; NOOFSIGFIGS : SIGFIGSRANGE ; ACTUALWIDTH : INTEGER ; BEGIN WITH BASICCHARS DO BEGIN SPLITUPREAL( VALUETOBEWRITTEN , DIGITS , DECEXPONENT , POSITIVE ) ; NOOFSIGFIGS := MIN(MAXSIGFIGS , MAX( 0 , DECEXPONENT + MAX( 0 , DECIMALPLACES ) ) ) ; ROUNDTONSIGFIGS( DIGITS , DECEXPONENT , NOOFSIGFIGS ) ; SIGNPOSITION := MAX( DECEXPONENT , 1 ) + 1 ; IF DECIMALPLACES <= 0 THEN START := MAX(SIGNPOSITION , WIDTH ) ELSE START := MAX( SIGNPOSITION , WIDTH - DECIMALPLACES - 1 ) ; FINISH := MIN( -DECIMALPLACES + 1 , 1 ) ; IF DECIMALPLACES <= 0 THEN ACTUALWIDTH := START - FINISH + 1 ELSE ACTUALWIDTH := START - FINISH + 2 ; IF (ACTUALWIDTH > WIDTH) OR (DECIMALPLACES < 0) THEN WRITE( F , ERRORCHAR ) ; FIRSTSIGDIGIT := DECEXPONENT ; LASTLEADINGZERO := MAX( FIRSTSIGDIGIT + 1 , FINISH ) ; LASTSIGDIGIT := MAX( DECEXPONENT - MAXSIGFIGS + 1 , FINISH ) ; FOR I := START DOWNTO SIGNPOSITION + 1 DO WRITE( F , SPACE ) ; IF POSITIVE THEN WRITE( F , SPACE ) ELSE WRITE( F , MINUS ) ; FOR I := SIGNPOSITION - 1 DOWNTO LASTLEADINGZERO DO BEGIN IF I = 0 THEN WRITE( F , POINT ) ; WRITE( F , ZERO ) ; END ; FOR I := FIRSTSIGDIGIT DOWNTO LASTSIGDIGIT DO BEGIN IF I = 0 THEN WRITE( F , POINT ) ; WRITE( F , CHR( DIGITS[ FIRSTSIGDIGIT + 1 - I ] + ORD( ZERO ) ) ) ; END ; FOR I := LASTSIGDIGIT - 1 DOWNTO FINISH DO BEGIN IF I = 0 THEN WRITE( F , POINT ) ; WRITE( F , ZERO ) ; END ; END ; END (* ICL9LPRIOWRFIX *) ; PROCEDURE ICL9LPRIOWRFLOAT(VALUETOBEWRITTEN : REAL ; WIDTH : INTEGER ; VAR BASICCHARS : CHARACTERSET ; VAR F : TEXT ) ; (* WRITES A REAL NUMBER TO A TEXT FILE IN FLOATING POINT FORMAT USING AT LEAST WIDTH CHARACTERS. DDD...DEDD IS SPACE(POSITIVE OR - (NEGATIVE) IS + OR - AT LEAST 2 AND NOT MORE THAN 16 SIGNIFICANT DIGITS ARE PRINTED. THE NUMBER IS ROUNDED TO THE APPROPRIATE NUMBER OF SIGNIFICANT FIGURES. IF WIDTH < 8 THE NMBER IS PRECEDED BY AN ASTERISK AND THEN PRINTED AS FOR WIDTH = 8. IF WIDTH > 22 THE NUMBER IS PRECEDED BY WIDTH - 22 SPACES. *) CONST MINWIDTH = 8 ; (* -D.DE+DD : MAXWIDTH IS 22, 16 DIGITS + '-.E+DD' *) VAR I : INTEGER ; DIGITS : DIGITSARRAY ; DECEXPONENT : -99 .. 99 ; POSITIVE : BOOLEAN ; NOOFSIGFIGS : SIGFIGSRANGE ; BEGIN WITH BASICCHARS DO BEGIN IF WIDTH < MINWIDTH THEN WRITE( F , ERRORCHAR ) ; WIDTH := MAX( WIDTH , MINWIDTH ) ; NOOFSIGFIGS := MIN( WIDTH - ( MINWIDTH - 2 ) , MAXSIGFIGS ) ; FOR I := 1 TO WIDTH - NOOFSIGFIGS - ( MINWIDTH - 2 ) DO WRITE( F , SPACE ) ; SPLITUPREAL( VALUETOBEWRITTEN , DIGITS , DECEXPONENT , POSITIVE ) ; IF POSITIVE THEN WRITE( F , SPACE ) ELSE WRITE( F , MINUS ) ; IF VALUETOBEWRITTEN <> 0 THEN DECEXPONENT := DECEXPONENT - 1 ; ROUNDTONSIGFIGS( DIGITS , DECEXPONENT , NOOFSIGFIGS ) ; WRITE( F , CHR( DIGITS[1] + ORD( ZERO ) ) , POINT ) ; FOR I := 2 TO NOOFSIGFIGS DO WRITE ( F , CHR( DIGITS[I] + ORD( ZERO ) ) ) ; WRITE( F , E ) ; IF DECEXPONENT < 0 THEN BEGIN WRITE( F , MINUS ) ; DECEXPONENT := - DECEXPONENT ; END ELSE WRITE( F , PLUS ) ; WRITE ( F , CHR( DECEXPONENT DIV 10 + ORD( ZERO ) ) , CHR( DECEXPONENT MOD 10 + ORD( ZERO ) ) ) ; END ; END (* ICL9LPRIOWRFLOAT *) ; BEGIN END.