Level 2, lesson 8

# 2.8 Pictured numeric output

You probably have used this before, like when writing Basic. Never heard of "PRINT USING.."? Well, it is a way to print numbers in a certain format. Like telephone-numbers, time, dates, etc. Of course 4tH can do this too. In fact, you've probably used it before. Both '.' and '.R' use the same internal routines. They are called just before a number is printed.

This numeric string is created in the PAD and overwritten with each new call. But we'll go into that a bit later on.

What you have to remember is that you define the format reverse. What is printed first, is defined last in the format. So if you want to print:

         060-5556916

You have to define it this way:

         6196555-060

Formatting begins with the word '<#' and ends with the word '#>'. A single number is printed using '#' and the remainder of the number is printed using '#s' (which is always at least one digit). Let's go a bit further into that:

         : print# <# #s #> type cr ;
         256 print#

This simply prints a single number (since only '#S' is between the '<#' and the '#>' and goes to a new line. There is hardly any difference with '.'. You can try any (positive) number. Note that the values that '#>' leaves on the stack can directly be used by 'TYPE'.

This is a slightly different format:

         : print3# <# # # # #> type cr ;
         256 print3#
         1 print3#
         1000 print3#

This one will print "256", "001" and "000". Always the last three positions. The '#' simply stands for 'print a single digit'. So if you want to print a number with at least three digits, the format would be:

         #s # #

That is: print the remainder of the number (at least one digit) and then two more. Now reverse it:

         # # #s

Enclose it by '<#' and '#>' and add 'TYPE CR':

         <# # # #s #> type cr

And that's it! Is it? Not quite. So far we've only printed *POSITIVE* numbers. If you try a negative number, you will find it prints garbage. This behaviour can be fixed with the word 'SIGN'.

'SIGN' simply takes the number from the stack and prints a "-" when it is negative. The problem is that all other formatting words can only handle positive numbers. So we need the same number twice. One with the sign and one without. A typical signed number formatting word looks like:

         : signed# dup abs <# #s sign #> type ;

Note the 'DUP ABS' sequence. First the number is duplicated (for 'SIGN') and then the absolute value is taken (for the other formatting words). So we got the on the stack twice. First with sign (for 'SIGN'), second without sign (for the other formatting words). Does that make sense to you?

We can place 'SIGN' wherever we want. If we want to place the sign after the number (like some accountants do) we would write:

         : account# dup abs <# sign #s #> type ;

But that is still not enough to write "$2000.15" is it? Well, in order to do that there is another very handy word called 'HOLD'. The word 'HOLD' just copies any character into the formatted number. Let's give it a try:

         $2000.16

Let's reverse that:

         61.0002$

So we first want to print two numbers, even when they are zero:

         # # .0002$

Then we want to print a dot. This is where 'HOLD' comes in. 'HOLD' takes an ASCII code and places the equivalent character in the formatting string. We don't have to look up the ASCII code for a dot of course. We can use 'CHAR':

         # # char . hold 0002$

Then we want to print the rest of the number (which is at least one digit):

         # # char . hold #s $

Finally we want to print the character "$". Another job for 'HOLD':

         # # char . hold #s char $ hold

So this is our formatting word:

         : currency <# # # char . hold #s char $ hold #> type cr ;

And we call it like this:

         200016 currency

You can do some pretty complex stuff with these formatting words. Try to figure out this one from the master himself, Leo Brody:

         : sextal 6 base ! ;
         : :00 # sextal # decimal 58 hold ;
         : time# <# :00 :00 #S #> type cr ;
         3615 time#

Yeah, it prints the time! Pretty neat, huh? Now try the telephone- number we discussed in the beginning. That shouldn't be too hard.