Formatted Numeric Output

May 18, 2012

It is often necessary for programs to produce numeric output in various formats, and most languages provide libraries for this purpose; for instance, C provides the printf function, which includes the d and f format specifications for decimal numbers (integers) and floating point numbers, respectively.

Your task is to write library functions that format integers and floating point numbers; you may follow the formatting conventions of C, or those of some other language, or invent your own. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Advertisement

Pages: 1 2

2 Responses to “Formatted Numeric Output”

  1. ardnew said

    This may not conform exactly with the proposed problem, but an interesting read regarding implementing printf for C++ programmers:

    http://insanecoding.blogspot.com/2010/03/c-201x-variadic-templates.html

  2. David said

    I thought it would be fun to implement the Dartmouth BASIC printing format. This was back in the days where formatting didn’t seem all the necessary as the computer printed how users intuitively expected things to go. In FORTH since that language (a) has a standard word to pick apart a floating point number and (b) default printing is rather unfriendly in that language.

    { ---------------------------------------------------------------------------
    Rules for printing Dartmouth BASIC numbers  (except allowing more than 6
    digits of precision, given the modern era of 64 bit FP.)
    
    Let P = desired output precision:
    
    1. If a number is an integer, the decimal point is not printed.  If the
       integer contains more than P digits, display in scientific notation with
       P significant digits.
    
    2. For any decimal number, no more than P significant digits are printed.
    
    3. For a number less than 0.1, the E notation is used unless the entire
       significant part of the number can be printed as a P decimal number.
       Thus, 0.01234578 means the number is exactly 0.012345678, while
       1.2345678E-2 means that the number has been rounded to 0.012345678
    
    4. Trailing zeros after the decimal point are not printed.
     --------------------------------------------------------------------------- }
    
    requires fpmath
    
    create fp-repr  20 chars allot
    create zero-str ,z" 00000000000000000" \ used to compare zero strings
    
    : fp-integer?  ( exp -- )
        dup precision >=          \ exponent > precision => integer
        swap precision over -     \ length to compare
        swap fp-repr + swap       \ address to compare
        zero-str over compare 0=  \ compare to all zeros
        or ;
    
    : (adjust)   ( addr count -- addr count' )
        over + 1-   \ addr end-addr
        BEGIN  dup c@ [char] 0 = WHILE
            1-
        REPEAT  over - 1+ ;
    
    : .sci  ( exp -- )
        fp-repr c@ emit
        [char] . emit
        fp-repr 1+ precision 1- (adjust) type
        [char] E emit
        dup 0> IF  [char] + emit  THEN
        . ;
    
    : .fp-integer ( exp -- )
        dup precision <= IF
            fp-repr swap type space
        ELSE
            1- .sci
        THEN ;
    
    : .fp-small  ( exp -- )
        fp-repr precision + 1- c@  [char] 0 = IF
            ." 0."
            negate 0 DO  [char] 0 emit  LOOP
            fp-repr precision (adjust) type
        ELSE
            1- .sci
        THEN ;
    
    : .fp   ( exp -- )
        dup IF
            dup fp-repr swap type
        ELSE
            [char] 0 emit
        THEN
        [char] . emit
        fp-repr over +  swap precision swap -  (adjust) type space ;
    
    : fp.   ( fp -- )
        fp-repr precision represent
        invert IF abort" Invalid FP value on stack." THEN
        ( sign ) IF  [char] - emit  THEN
    
        fp-repr c@ [char] 0 = IF   \ zero special case
            drop ." 0" exit
        THEN
        dup fp-integer? IF
            .fp-integer exit
        THEN
        dup 0<    \ <= 10^-1
            IF .fp-small exit
        THEN
        ( ELSE ) .fp ;
    

    Some tests:

    0e fp. 0 ok
    2e fsqrt fp. 1.41421356237  ok
    944,221,771,433,788 d>f fp. 9.44221771434E+14  ok
    0.00875e fp. 0.00875 ok
    0.00877777777777777e fp. 8.77777777778E-3  ok
    -25.75e fp. -25.75  ok
    255e fp. 255  ok
    49e fsqrt fp. 7  ok
    0.530000e fp. 0.53  ok
    6 set-precision  ok
    676,211,477,636,211 d>f f. 676211000000000.  ok
    676,211,477,636,211 d>f fp. 6.76211E+14  ok
    

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: