Classic Computer Magazine Archive COMPUTE! ISSUE 9 / FEBRUARY 1981 / PAGE 30


Jim Butterfield

It's handy to be able to arrange numbers neatly in columns. Computers having the PRINT USING statement help you do this. If your machine hasn't got a PRINT USING, however, you'll need to do it some other way.

There are many methods of producing this kind of output. One of the better ones involves extracting the digits, one at a time, and then printing them; this method is a little slow in Basic because of the arithmetic involved.

I've put together a quick and fairly fast subroutine to help you do the job. The actual coding is eight Basic lines, so it won't take up too much space. To allow for maximum flexibility, you are permitted to name how many digits you want to allow before the decimal point, and how many after.

The subroutine takes your value V and gives you back a string, V$, which you can then print. String V$ contains the leading spaces and trailing zeros to fit the space you have specified.

The length of V$ can be worked out this way: You will have specified how many digits you want before the decimal point as variable V1 and after the decimal point as variable V2. Add these two values together; then add one for the sign and one more for the decimal point. Exception: If you've specified V2 as zero, meaning you want no digits after the decimal point, the decimal point itself will be dropped.

Images, Pictures and Patterns

There are many possible features of a PRINT USING system that are not included in this short subroutine. You should know about them; perhaps you would like to try your hand at adding some of them.

A floating dollar sign allows the dollar sign to move up snugly against the number itself. A fill character fills up all the spaces before the first digit of the number; it's most often used with the asterisk character, to give an output that looks like ***** 12.47 for printing cheques.

Comma insertion allows you to punctuate large numbers, to give an output like 3,827, 149. Negative numbers often have many ways of display: examples are -437.22, (437.22) and 437.22CR. Variable Zero Suppression allows you to choose whether to print a value of five cents as .05, 0.05, or 00.05.

The above features, if included, would make the subroutine bigger and slower. Apart from a floating minus sign, they are not there; but a couple of features have been included which are important for financial printouts.

All numbers are carefully rounded, so that a value of 12.387 will convert to 12.4 if you choose to show one place after the decimal.

Overflow is tested: it would be annoying or disastrous to have a value of 12345 printed as 345 just because you asked for three digits before the decimal! Situations like this are flagged by the printing of asterisks instead of the number.

There's one type of overflow that doesn't cause asterisks to be printed, but in this case you're unlikely to mistake it for a genuine value. Occasionally, when you have a number like one million, the STR$ function will convert it to a string like "1E + 09" rather than the "1000000000" we might expect. (Why the extra zeros? They are intended to go behind the decimal point). This causes an oddlooking output of something like "1E. + 09" which won't be mistaken for a real number. If this bothers you, you could add extra coding to spot it. It's probably better, however, to think of overflow as a debugging tool — it must never, never happen in your final polished program.

You should try to keep the number of digits (V1 plus V2) not greater than 9. If you really want to print amounts well over a million dollars with accuracy to the penny, you're starting to push against the limits of 32-bit Basic; rounding errors will start to steal the occasinal penny away from you.

The Program

Line 50020 changes V to a rounded integer, and 50030 converts to a string. At this point, 3.14159 becomes the string " 3142" with spaces at the front padding out the string to the right length.

Line 50040 skips decimal point insertion if we don't need it. Otherwise, line 50050 checks to see if there are any spaces behind where we want to place the decimal point. For example, the value .014 might be held as " 14 ", and we'll need to re-insert the missing zero. Variables V5 and V6 will do this for us, if needed.

Note that line 50050 leaves an "unclosed" loop on the stack. So long as this is a subroutine, it won't give us any problem: the loop will be closed when the subroutine performs RETURN.

Line 50070 puts in the decimal point and any needed zeros. Finally, line 50080 checks for overflow and substitutes asterisks if needed.

The test program, lines 100-170, produces both very large and very small numbers, both positive and negative.

110 FOR J = 1 to 20
120 V = EXP (RND (1)*14-6)* SGN(RND(1)-.2)
130 V1 = 4 : V2 = 0 : GOSUB 50000: PRINTV$; " ";
140 V1 = 3 : V2 = 1 : GOSUB 50000; PRINTV$; " ";
150 V2 = 4 : GOSUB 50000 : PRINT V$
160 NEXT J
170 END
50020 V4 = INT(V * 10 ↑ V2 + .5)
50030 V$ = RIGHT$(" " + STR$(V4), V1 + V2 + 1)
50040 IF V2 < 1 GOTO 50080
50050 FOR V5 = V1 + 2 TO V1 + V2 + 1 : IF ASC (MID$(V$, V5)) < 48 THEN NEXT V5
50060 V6 = V5 - V1 - 1
50070 V$ = MID$(V$, V6, V1 + 1) + LEFT$(". 00000", V6) + MID$(V$, V5)
50080 IF ASC(V$)> 47 THEN V$ = LEFT$ ("**********", V1 + V2 + 2 + (V2 =0))
50090 RETURN