Revision 2014-05-31
\ FGOUT.F version 1.0
\
\ Output floating-point numbers in FORTRAN 'G' format
\
\ Main words:
\
\ (FG.) ( r n -- c-addr u )
\
\ Convert real number r to a string c-addr u with n digits
\ of precision. Fixed-point notation is used if the
\ exponent is in the range -1 to n otherwise use scientific
\ notation.
\
\ FG.R ( r n u -- )
\
\ Display real number r right-aligned in a field width u
\ with n digits of precision. Fixed-point notation is used
\ if the exponent is in the range -1 to n otherwise use
\ scientific notation.
\
\ Notes:
\
\ Output is of the form produced by FORTRAN edit descriptor
\ 1PGw.d
\
\ Two implementation strategies are provided. The default
\ method uses REPRESENT to build the output from scratch.
\ Alternatively if your system has (FS.) or equivalent
\ then string manipulation can be used to transform its
\ output into the required form.
\
\ For use with separate or common stack floating-point
\ Forth models. Uses the pictured numeric output buffer.
\
\ This code is PUBLIC DOMAIN. Use at your own risk.
\
FORTH DEFINITIONS DECIMAL
\ Tools
\ Display string c-addr u right-justified in a field of
\ width characters
: S.R ( c-addr u width -- )
OVER - SPACES TYPE ;
\ *******************************************************
\ Choose an implementation method 1=default, 0=alternate
\ *******************************************************
1 [IF] CR .( Compiling REPRESENT version )
\ This implementation is expected to function correctly with
\ most implementations of REPRESENT. Should yours be found
\ wanting, a basic REPRESENT implementation is available at
\ the DX-Forth website.
\ HOLD for strings
: SHOLD ( c-addr u -- )
BEGIN DUP WHILE 1- 2DUP CHARS + C@ HOLD REPEAT 2DROP ;
[UNDEFINED] MAX-PRECISION [IF]
S" MAX-FLOAT-DIGITS" ENVIRONMENT? 0= [IF]
CR .( MAX-FLOAT-DIGITS not found substituting: )
CR .( MAX-PRECISION = ) 15 DUP .
[THEN] CONSTANT MAX-PRECISION
[THEN]
S" REPRESENT-CHARS" ENVIRONMENT? 0= [IF]
MAX-PRECISION
[THEN] CONSTANT maxchars
CREATE buf maxchars CHARS ALLOT
: (mant) ( u prec -- )
OVER buf -ROT /STRING SHOLD
[CHAR] . HOLD buf SWAP SHOLD ;
\ Convert real number r to string c-addr u with n digits of
\ precision. Fixed-point notation is used if the exponent is
\ in the range -1 to n otherwise use scientific notation.
: (FG.) ( r n -- c-addr u )
MAX-PRECISION MIN 1 MAX >R
buf R@ REPRESENT <# IF
SWAP DUP 0 R@ 1+ WITHIN IF
S" " SHOLD R@ (mant) 0 0
ELSE
1- DUP ABS 0 # #S ROT
0< IF [CHAR] - ELSE [CHAR] + THEN HOLD
[CHAR] E HOLD 1 R@ (mant)
THEN ROT SIGN
ELSE
( S" " SHOLD ) buf maxchars -TRAILING SHOLD
THEN #> R> DROP ;
[ELSE] CR .( Compiling string manipulation version )
\ This implementation assumes the existence of a function:
\
\ (FS.) ( r n -- c-addr u )
\
\ Convert real number r to string c-addr u in scientific
\ notation with n places right of the decimal point.
\
\ whose output is in the form:
\
\ [-]x.xxxxxE+/-yy
\
\ The exponent character must be 'E' followed by a sign '+'
\ or '-'. If the number of mantissa/exponent digits is fixed
\ then the output will be aligned. If a decimal point is not
\ present then r is assumed to be non-finite and the string
\ is passed unchanged.
\ Split string at char
: SPLIT ( a u char -- a2 u2 a u-u2 )
>R 2DUP R> SCAN 2SWAP 2 PICK - ;
variable dpos
2variable estr
\ Convert real number r to string c-addr u with n digits of
\ precision. Fixed-point notation is used if the exponent is
\ in the range -1 to n otherwise use scientific notation.
: (FG.) ( r n -- c-addr u )
\ FDP @ FECHAR C@ 2>R 1 FDP ! [CHAR] E FECHAR C!
1 MAX 1- (FS.)
2DUP [CHAR] . SPLIT 2DROP DUP IF ( not NAN/INF)
[CHAR] E SPLIT >R dpos ! 2DUP estr 2! 1 /STRING
OVER C@ [CHAR] - = >R 1 /STRING
0 0 2SWAP >NUMBER 2DROP R> IF DNEGATE THEN D>S
DUP -1 R@ WITHIN IF
DUP >R dpos @ DUP R@ 0< IF 1- ELSE 1+ THEN SWAP
R@ ABS CHARS MOVE [CHAR] . dpos @ R> CHARS + C!
estr 2@ ( 1 /STRING ) BLANK
THEN R>
THEN 2DROP
\ 2R> FECHAR C! FDP !
;
[THEN]
\ Display real number r right-justified in a field width u
\ with n digits of precision. Fixed-point notation is used
\ if the exponent is in the range -1 to n otherwise use
\ scientific notation.
: FG.R ( r n u -- )
>R (FG.) R> S.R ;
\ Test the function
0 [IF]
3.14159265358979324E FCONSTANT pi
pi FNEGATE FCONSTANT -pi
VARIABLE prec 3 prec !
VARIABLE wid 15 wid !
: d.w ( -- prec width ) prec @ wid @ ;
: test ( -- )
CR d.w ." Width=" . ." Prec=" .
CR -pi 1E6 F* d.w FG.R
CR pi 1E5 F* d.w FG.R
CR -pi 1E4 F* d.w FG.R
CR pi 1E3 F* d.w FG.R
CR -pi 1E2 F* d.w FG.R
CR pi 1E1 F* d.w FG.R
CR -pi 1E0 F* d.w FG.R
CR 0.0E d.w FG.R
CR pi 1E-1 F* d.w FG.R
CR -pi 1E-2 F* d.w FG.R
\ CR 1.E 0.E F/ d.w FG.R ( +Infinity on 80x87)
\ CR 0.E 0.E F/ d.w FG.R ( -NaN on 80x87)
;
3 prec ! 15 wid ! test
6 prec ! 15 wid ! test
[THEN]
\ end
Width=15 Prec=3
-3.14E+06
3.14E+05
-3.14E+04
3.14E+03
-314.
31.4
-3.14
0.00
.314
-3.14E-02
+INF
-NAN
Width=15 Prec=6
-3.14159E+06
314159.
-31415.9
3141.59
-314.159
31.4159
-3.14159
0.00000
.314159
-3.14159E-02
+INF
-NAN
Top Home Forth
![]()
Page updated: 31 May 2014