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