Simple Floating-Point Output

Revision  2013-10-29

This simple floating-point output package has features found in more comprehensive implementations yet
is remarkably compact and portable. Based on code and algorithm from Forth Inc.

\ SFPOUT.F
\
\ Simple Floating Point Output
\
\ Main words:
\
\ (F.)  (FS.)  (FE.)  F.R  FS.R  FE.R  F.  FS.  FE.
\ FDP  PLACES
\
\ This package should function correctly on any Forth
\ system with the following limitations:
\
\ - Don't attempt to output non-numbers such as NANs
\   or INFs as it will enter an infinite loop.
\ - Floating-point strings are limited to the size of
\   the system's pictured numeric output buffer.
\
\ History:
\ 131029  Fix (F.) to use FDP. Add F. FS. FE. PLACES

FORTH DEFINITIONS DECIMAL

\ Floating-point pictured numeric output operators
: <#. ( F: r1 -- r2 )  FROUND <# ;
: #. ( F: r1 -- r2 )  10.E F/ FDUP FLOOR FSWAP FOVER F-
  10.E F* FROUND F>D D>S  [CHAR] 0 + HOLD ;
: #S. ( F: r1 -- r2 )  BEGIN #. FDUP F0= UNTIL ;
: #>. ( F: r -- ) ( c-addr u )  FDROP 0 0 #> ;
: SIGN. ( flag -- )  IF [CHAR] - HOLD THEN ;

\ Variable controlling trailing decimal point display.
\ Default (ON) is to always display decimal point.
VARIABLE FDP  1 FDP !

: 10^n ( r1 n -- r2 )  0 ?DO 10.E F* LOOP ;
: #.n ( r1 n -- r2 )  0 ?DO #. LOOP ;

VARIABLE rscale  1 rscale !
FVARIABLE rstep  10.E rstep F!
VARIABLE fdpl  4 fdpl !

\ Normalize to range 1.0 <= r < STEPSIZE
: fnorm ( r1 -- |r2| sign exp )
  FDUP F0<  0 2>R  FABS
  FDUP F0= 0= IF
    BEGIN  FDUP  rstep F@ F< 0=
    WHILE  rstep F@ F/  R> rscale @ + >R  REPEAT
    BEGIN  FDUP 1.0E F<
    WHILE  rstep F@ F*  R> rscale @ - >R  REPEAT
  THEN  2R> ;

\ Convert fixed-point
: fcvt ( r n -- )
  >R  FDUP F0< ( sign)  R> 2>R
  FABS  FDP @ IF  ( always output decimal point )
    R> #.n  [CHAR] . HOLD
  ELSE  ( conditionally output decimal point )
    R@ #.n  R> IF  [CHAR] . HOLD  THEN
  THEN  #S.  R> SIGN.  #>. ;

\ Convert real number r to string c-addr u in exponential
\ notation with n places right of the decimal point.
: (e.) ( r n scale step -- c-addr u )
  rstep F!  rscale !  0 MAX >R  fnorm
  R> 2>R  IF FNEGATE THEN  1.E R@ 10^n
  FSWAP FOVER F*  FROUND ( make integer)
  FDUP FABS FROT F/ rstep F@ F< 0= IF ( overflow)
  rstep F@ F/  R> R> rscale @ + >R >R  THEN
  <#.  R>  R> S>D TUCK DABS # #S  2DROP
  0< IF [CHAR] - ELSE [CHAR] + THEN  HOLD
  [CHAR] E HOLD  fcvt ;

\ Convert real number r to string c-addr u in scientific
\ notation with n places right of the decimal point.
: (FS.) ( r n -- c-addr u )  1 10.E (e.) ;

\ Display real number r in scientific notation right-
\ justified in a field width u with n places right of
\ the decimal point.
: FS.R ( r n u -- )  >R (FS.) R> OVER - SPACES TYPE ;

\ Convert real number r to string c-addr u in engineering
\ notation with n places right of the decimal point.
: (FE.) ( r n -- c-addr u )  3 1000.E (e.) ;

\ Display real number r in engineering notation right-
\ justified in a field width u with n places right of
\ the decimal point.
: FE.R ( r n u -- )  >R (FE.) R> OVER - SPACES TYPE ;

\ Convert real number r to string c-addr u in fixed-point
\ notation with n places right of the decimal point.
: (F.) ( r n -- c-addr u )
  0 MAX  DUP >R  10^n  <#. ( round)  R> fcvt ;

\ Display real number r in fixed-point notation right-
\ justified in a field width u with n places right of
\ the decimal point.
: F.R ( r n u -- )  >R (F.) R> OVER - SPACES TYPE ;

\ Set decimal places control for F. FS. FE.
: PLACES ( n -- )  fdpl ! ;

: F.  ( r -- )  fdpl @ 0 F.R SPACE ;
: FS. ( r -- )  fdpl @ 0 FS.R SPACE ;
: FE. ( r -- )  fdpl @ 0 FE.R SPACE ;

[DEFINED] DXFORTH [IF] behead 10^n (e.) [THEN]

\ end

Top    Home    Forth

em.gif (457 bytes)


web analytics

Page updated: 29 Oct 2013