Numbers Are No No’s

Authors

Publication

Pub Details

Date

Pages

See all articles from SyncWare News v1

One of the big advantages of the T/S machine is also one of its disadvantages; its five-byte floating point binary numbers allow for 10-place decimal accuracy, but take more space to store than four-byte numbers, What’s more, its BASIC uses floating point numbers, allowing calculated GOTO/GOSUB, FOR/NEXT in fractional steps, and other nifty things, But again, it’s at the expense of memory space that we get these features.

Let’s start out by counting the bytes in a “typical” program line, e.g. 10 PRINT 0. Well, the line number takes two bytes, length of line takes two bytes, and end of line marker (ENTER character) takes one. So it takes 5 bytes to define the line. The PRINT takes one byte and the 0 takes one, right? Wrong! The total length of this line is not 7 but 13 bytes — almost twice as long as it looks! Enter the following program (ZX81/TS1000/1500) to see why:

10 PRINT 0
20 LIST
30 LET A=16509
40 PRINT A;" - ";PEEK A,CHR$ PEEK A
50 LET A=A+1
60 GOTO 40

RUN the program. You’ll see the contents of the first program line displayed under the listing. Here I should note that most two-byte integers are stored (and used by CPU) “backwards” — i.e. LESS significant byte first. The exception (there’s always an exception) is the line numbers of BASIC programs, which is less significant byte LAST. So locations 16509 and 16510 give the line number as 0*256+10=10, and 16511 and 16512 give # of bytes as 9+256*0=9. 16513 contains the PRINT, and 16514 is the “0.” But what’s all that other garbage before the 118 end-of-line marker? Well, first there is a 126 that tells the LISTing routine that the previous expression (0 in this case) is a number, followed by the five-byte binary equivalent of that number. The bottom line is that every time you use a number in a program, you use up six bytes that don’t show in the listing. Change line 10 and run the program after each change, Try PRINT 1, LET C=PI, PRINT AT 0,0;0 etc. (This last one won’t all fit on the screen; enter CONT to see as far into the program as you like.)

“What a waste!” you might well exclaim. But there’s something you can do to reduce this wasted space — avoid numbers in program listings whenever possible. “What? Compute without numbers?” Well, not exactly. What we need to avoid is FLOATING-POINT numbers in program listings. As you saw, it takes seven bytes to store even as “trivial” a number as zero or one.

One way is to refer to zero and one as NOT PI and NOT NOT PI, respectively. (Paul Holmgren suggested an even better one for 1 = SGN PI.) You could replace -1 with COS PI, I’m sure you can find others. Since most programs contain lots of zeros and ones, you can save a lot of memory by this technique.

Another way of avoiding floating point is to use VAL. E.g. GOTO VAL “1130” instead of GOTO 1130. This saves an automatic 3 bytes each use. This is great for one-time GOTOs as in menus, POKEs, USR calls etc, but is appreciably slower; so, for inside loops and so on, you’ll have to balance speed against economy when considering this.

Perhaps the most powerful technique is to use variables for the often-used numbers in your program. Change line 10 to PRINT B, enter LET B=0, then enter GOTO 10. Even though variable B represents a floating-point number, it takes only one byte to store “B” in the program listing. It takes six bytes to store this variable in the variables area, of course; but it’s stored only once, so the more often you use B in the program listing instead of 0, the more memory you save. For example, if you use 0 fifty times in the program (not all that much, really) you’ll save close to 300 bytes by using a one-letter variable instead. Even if you add LET statements at the beginning of your program to define the constants, you’ll still save memory if you use that constant more than 3 times. This has the advantage of making the program RUNable. If you’re really squished for space, you can always delete the defining lines and remember to only use GOTO in the future, and to be as careful with RUN and CLEAR as you are with NEW.

Using up one-letter variables for constants is not recommended for larger programs, where you need them for your various true variables and FOR/NEXT variables. For scrunching a large program, a better approach is to use variables like N0=0, N1=1, … , O0=10, … P0=20, P1=21, etc. as needed. Commonly used subroutine numbers can be replaced with S1, S2, etc. While your savings won’t be as great with two byte names, they are still quite appreciable. For numbers not used often enough to merit their own variable but which are expressible as a simple function of existing constants, you can save a few bytes by using an expression. E.g. if O0=10 and P0=20, then we can say GOTO O0*PO instead of GOTO 200 and save four bytes (and still run a good deal faster than using VAL.) The N?, 0?, P? decade approach is almost as easy to read “real” numbers, and it’s not an unconfrontable task to go through an existing program and edit the letters before each “target” number.

Experiment with this using any of the available “bytes remaining” routines to measure your progress in economizing memory. You might be surprised how much you can stretch your RAM with these approaches. Until next time, happy pynching!

Products

 

Downloadable Media

 
Scroll to Top