## 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.

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:

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 ;

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
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
```