Node:Formatted numeric output, Next:String Formats, Previous:Simple numeric output, Up:Other I/O

Forth traditionally uses a technique called pictured numeric
output for formatted printing of integers. In this technique, digits
are extracted from the number (using the current output radix defined by
`base`

), converted to ASCII codes and appended to a string that is
built in a scratch-pad area of memory (see Implementation-defined options). Arbitrary characters can be appended to the string during the
extraction process. The completed string is specified by an address
and length and can be manipulated (`TYPE`

ed, copied, modified)
under program control.

All of the integer output words described in the previous section (see Simple numeric output) are implemented in Gforth using pictured numeric output.

Three important things to remember about pictured numeric output:

- It always operates on double-precision numbers; to display a single-precision number, convert it first (for ways of doing this see Double precision).
- It always treats the double-precision number as though it were unsigned. The examples below show ways of printing signed numbers.
- The string is built up from right to left; least significant digit first.

Initialise/clear the pictured numeric output string.`<#`

--core ``less-number-sign''

Start a hold area that ends with`<<#`

--gforth ``less-less-number-sign''

`#>>`

. Can be nested in
each other and in `<#`

. Note: if you do not match up the
`<<#`

s with `#>>`

s, you will eventually run out of
hold area; you can reset the hold area to empty with `<#`

.
Used within`#`

ud1 -- ud2core ``number-sign''

`<#`

and `#>`

. Add the next
least-significant digit to the pictured numeric output
string. This is achieved by dividing `base`

to leave quotient `#`

will append a "0"
to the string.
Used within`#s`

ud -- 0 0core ``number-sign-s''

`<#`

and `#>`

. Convert all remaining digits
using the same algorithm as for `#`

. `#s`

will convert
at least one digit. Therefore, if `#s`

will append
a "0" to the pictured numeric output string.
Used within`hold`

char --core ``hold''

`<#`

and `#>`

. Append the character
Used within`sign`

n --core ``sign''

`<#`

and `#>`

. If `#>`

, as shown in the examples below.
Complete the pictured numeric output string by discarding`#>`

xd -- addr ucore ``number-sign-greater''

Release the hold area started with`#>>`

--gforth ``number-sign-greater-greater''

`<<#`

.
`represent`

r c-addr u -- n f1 f2float ``represent''

Convert`f>str-rdp`

rf +nr +nd +np -- c-addr nrgforth ``f>str-rdp''

`f.rdp`

. The result in in the pictured numeric output buffer
and will be destroyed by anything destroying that buffer.
doc-f>buf-rdp

Here are some examples of using pictured numeric output:

: my-u. ( u -- ) \ Simplest use of pns.. behaves like Standard u. 0 \ convert to unsigned double <<# \ start conversion #s \ convert all digits #> \ complete conversion TYPE SPACE \ display, with trailing space #>> ; \ release hold area : cents-only ( u -- ) 0 \ convert to unsigned double <<# \ start conversion # # \ convert two least-significant digits #> \ complete conversion, discard other digits TYPE SPACE \ display, with trailing space #>> ; \ release hold area : dollars-and-cents ( u -- ) 0 \ convert to unsigned double <<# \ start conversion # # \ convert two least-significant digits [char] . hold \ insert decimal point #s \ convert remaining digits [char] $ hold \ append currency symbol #> \ complete conversion TYPE SPACE \ display, with trailing space #>> ; \ release hold area : my-. ( n -- ) \ handling negatives.. behaves like Standard . s>d \ convert to signed double swap over dabs \ leave sign byte followed by unsigned double <<# \ start conversion #s \ convert all digits rot sign \ get at sign byte, append "-" if needed #> \ complete conversion TYPE SPACE \ display, with trailing space #>> ; \ release hold area : account. ( n -- ) \ accountants don't like minus signs, they use parentheses \ for negative numbers s>d \ convert to signed double swap over dabs \ leave sign byte followed by unsigned double <<# \ start conversion 2 pick \ get copy of sign byte 0< IF [char] ) hold THEN \ right-most character of output #s \ convert all digits rot \ get at sign byte 0< IF [char] ( hold THEN #> \ complete conversion TYPE SPACE \ display, with trailing space #>> ; \ release hold area

Here are some examples of using these words:

1 my-u. 1 hex -1 my-u. decimal FFFFFFFF 1 cents-only 01 1234 cents-only 34 2 dollars-and-cents $0.02 1234 dollars-and-cents $12.34 123 my-. 123 -123 my. -123 123 account. 123 -456 account. (456)