Optimizing your TI-92 programs
Have you ever wanted to know how to make your programs just a tinny bit faster? I mean your program is almost fast enough to be fun, but something is holding it back? If you answer yes to either of these questions then this tutorial is for you.
Here are the programs I tested:
Program using 'If' statements asf() Prgm Local a,b {10,-1}->b Pause "start" For a,1,100 b[mod(a,2)+1]->xc b[mod(a,2)+1]->yc if xc<0:0->xc if xc>10:10->xc if yc<0:0->yc if yc>10:10->yc EndFor Disp "done" EndPrgm Program using 'When' statements asd() Prgm Local a,b {10,-1}->b Pause "start" For a,1,100 b[mod(a,2)+1]->xc b[mod(a,2)+1]->yc when(xc<0,0,when(xc>10,10,xc))->xc when(yc<0,0,when(yc>10,10,yc))->yc EndFor Disp "done" EndPrgm
Which of the programs do you think was smaller?
Which was faster?
Characters | After Tokenization | Time to execute | Cycles per second | |
Using If commands | 180 | 179 bytes | 9.48 Seconds | 10.5485 |
Using When commands | 190 | 165 bytes | 8.48 Seconds | 11.7924 |
As you can see, the When command won by a full second and used 14 less bytes when tokenized.
So what is this magic tokenization?
Tokenizing is where before the calculator can use a basic program it must interpret the lines so as to be able to run faster. This is the reason after editing a program there is a small (or large) pause before the program can run. This is also why the calculator can tell you right away that there is a syntax error. During tokenization, the calculator changes most (not all) keywords into a byte or two, depending on what it is, and this is why even though the When program takes up 10 more characters, after tokenization it takes up 14 less. Remember returns and colons take up a byte each, and variable names are not tokenized.
So, why is this faster?
If you look at the code, you will notice that the when command inside the when command is only called when the first test is false. So, does the storing take up more time, for every time you are doing that? Yes, the storing does take up extra time. However, to store into a variable takes about .0105 seconds. This time does add up, but doing two extra comparisons every other time and phrasing the two other lines every time takes up an extra second ever 100 iterations.
Big deal, 100 times is a lot of iterations.
If you are so sure, then type in both programs and tell me which one you would rather have in a program that you use everyday. I bet you would rather run a program that is about 11.792% faster than the other one. How many times might a game use this? A lot.
So, how do I use this in my program?
I would suggest that when you have a bounds checking routine instead of using this:
if xc<0:0→xc if xc>10:10→xc if yc<0:0→yc if yc>10:10→yc
Use:
when(xc<0,0,when(xc>10,10,xc))→xc when(yc<0,0,when(yc>10,10,yc))→yc
The lesson is not just use when's where you can instead of if's, but it is to time your routines and discover what is slow and then try ways to get around it, such as using when's. Remember to look in the manual and find commands that are close to what you want so you can get them done faster, because sure it's fun to write you own sorting algorithm, instead of using SortA or SortD. But who is going to want to use your program or game if someone else has one that is twice as fast, or half as big?
Lots of Routine Times | ||
500 iterations | Size | Seconds to execute |
---|---|---|
For | 78 bytes | 5.10 seconds |
While | 90 bytes | 8.71 seconds |
Loop | 100 bytes | 9.44 seconds |
Goto | 94 bytes | 10.75 seconds |
100 iterations | Seconds to Execute | |
Indirection to an array (using a mod) | 3.32 Seconds | |
Direct to an array (using a mod) | 3.00 seconds | |
Indirection to an array (single spot) | 2.83 Seconds | |
Direct to an array (single spot) | 2.46 seconds | |
Indirection to a variable | 3.26 seconds | |
Direct to a variable | 2.80 seconds | |
50 iterations | size | Seconds to execute |
If...Then...Else (True and False actions) | 138 bytes | 2.67 seconds |
2 If...Then commands (True and False actions) | 147 bytes | 3.08 seconds |
4 if commands (true and false actions) | 157 bytes | 3.80 seconds |
If...Then (Only a true action) | 116 bytes | 1.32 seconds |
2 If commands (Only a true action) | 121 bytes | 1.66 seconds |
When commands (Only a true action) | 121 bytes | 3.01 seconds |
100 iterations | Seconds to execute | |
Left (first 5 chars of a 10 char string) | 2.45 seconds | |
Right (last 5 chars of a 10 char string) | 2.45 seconds | |
Mid as a left | 2.53 seconds | |
Mid as a right | 2.45 seconds | |
Unoptimized mid as a right | 2.53 seconds | |
100 stores | 1.05 seconds | .0105 seconds a store |
I hope that these benchmarks will assist you in writing the fastest game or program possible in BASIC. A few more tips and I'll be done.
Never use goto's if you can help it. One, it is slow. Two, if you leap out of a control structure you waste memory in the stack, which means that exit, cycle and other commands will not work correctly (unless that is what you want :) and when stack space is wasted all other commands slow down so overall making your program slower, plus eventually when the stack space is filled and you'll get a memory error or maybe even a crash. Goto's have their place and their place is only where loop's, while's and for's will not work.
Space is important on a calc that has a limited amount memory. If your program needs large fancy graphics or small icons you must keep the size to a minimum. Try out Vector Man if you need full screen graphics. You just draw the graphics you want in Vector Man and it will spit out programs that draw it for you. Definitely try Icon Maker for tiles in a game as it makes them quickly and easily. Okay enough plugging for my programs. What I mean is if you need or want full screen graphics use the drawing commands as they often save space, which is at a premium. When using pictures use several if the picture is showing a logo, a lot of blank space, and some icons. It will save space, maybe 500-600 bytes, and often a little space is all the user wants when your program is deleted.