Output Floating-Point Numbers in FORTRAN 'G' Format

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

Test output

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

em.gif (457 bytes)


web analytics

Page updated: 31 May 2014