More comments from the first ELSE article… First, MiaM chimes in:
You could also split that to two separate statements. One handling K=17 case, and then do ON K-38 GOTO 50,x,30 where x is just the line following the ON GOTO line.
don’t know about speed but you could also try ON K-16 GOTO 40,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,50,x,x,30 (also where x is the following line)MiaM
In my example, I was getting keypress values back that represented left (17), right (39) and jump (41). By filling the ON/GOTO/GOSUB with bogus line values where the gaps are, you can now use ON/GOTO for non-sequential values. But, if the first number expected was a 17, that would be 17 dummy values at the start. Mia’s approach is to subtract that starting value, eliminating the need for 16 dummy values. Clever!
Clever, sure. But can it be benchmarked?
So how bad is this with speed? Let’s find out.
First, for the dummy lines we will just put nothing between the commas. That will be parsed as a zero, which is bad if any of those values are hit since going to 0 would restart the program, but since we are just testing and can control the value, it will give us the fastest way to parse a long ON/GOTO/GOSUB. Using real lines numbers will only be slower.
0 REM ONMIAM.BAS 5 DIM TE,TM,B,A,TT 6 K=17 'BEST CASE 10 FORA=0TO3:TIMER=0:TM=TIMER 20 FORB=0TO1000 30 ON K-16 GOTO 100,,,,,,,,,,,,,,,,,,,,,,200,,300 70 NEXT 80 TE=TIMER-TM:PRINTA,TE 90 TT=TT+TE:NEXT:PRINTTT/A:END 100 REM LEFT 110 GOTO70 200 REM RIGHT 210 GOTO70 300 REM JUMP 310 GOTO70
Best case for the first target gives me 590. Not bad!
Trying again with “K=41” for worst case gives us 664. Still not terrible.
How does this rank against manual IF/THENs like this?
0 REM ONMIAM2.BAS 5 DIM TE,TM,B,A,TT 6 K=17 'BEST CASE 10 FORA=0TO3:TIMER=0:TM=TIMER 20 FORB=0TO1000 30 IF K=17 THEN 100:GOTO 70 40 IF K=39 THEN 200:GOTO 70 50 IF K=41 THEN 300 70 NEXT 80 TE=TIMER-TM:PRINTA,TE 90 TT=TT+TE:NEXT:PRINTTT/A:END 100 REM LEFT 110 GOTO70 200 REM RIGHT 210 GOTO70 300 REM JUMP 310 GOTO70
Best case (17) reports 504 and worst case (41) reports 1128. Can there really be that much more overhead to skip two extra IF/THENs? It seems so. In this example, the long ON/GOTO is faster in worst case. Interesting. If worst case is a button not used that often (“smart bomb”), IF/THEN may be the best option, but if all buttons are used equally, there’s probably a point where a long ON/GOTO makes more sense.
But wait … there’s more!
Rob provided a suggestion about using an array:
Yep, could also do something likeRob
ON C(K) GOSUB 20,30,40
But that’s probably a bit memory hungry.
Rob’s idea of using an array to translate the non-sequential values into sequential numbers is a fun one. It uses more memory, and trades the time it takes to do an array lookup for the time it takes to parse a long ON/GOTO/GOSUB line.
0 REM ONMIAM2.BAS 5 DIM TE,TM,B,A,TT 6 K=17 'BEST CASE 7 DIMK(41):K(17)=1:K(39)=2:K(41)=41 10 FORA=0TO3:TIMER=0:TM=TIMER 20 FORB=0TO1000 30 ON K(K) GOTO 100,200,300 70 NEXT 80 TE=TIMER-TM:PRINTA,TE 90 TT=TT+TE:NEXT:PRINTTT/A:END 100 REM LEFT 110 GOTO70 200 REM RIGHT 210 GOTO70 300 REM JUMP 310 GOTO70
Since the largest value we need to check for is 41, I did a DIM K(41). That will allow for values from 0 to 41.
Best case (17) gives us 432! Faster than the manual IF/THEN check!
Worse case (41) gives us 432 … Really? ON/GOTO is really fast with just a few choices. It would be slower if there were dozens and you wanted the one at the end.
The downside of this approach is the memory it took for an array of 42 (0-41) variables. Doing something like this:
NEW:CLEAR PRINT MEM DIM K(41) PRINT MEM
…shows me 22823 and 22606. That’s 217 bytes being taken by the 42 K array entries. (There is an entry reserved for the array itself, then each array element takes 5 bytes, I believe. It’s been awhile since I wrote my String Theory articles which I think looked into how variables are stored.)
This may be the fastest approach if you have a few hundred bytes available to use for this. On a VIC-20 with 3583 bytes free on startup, if I had memory left when I was done with my normal IF/THEN version, I could retrofit it with this approach and use that extra available RAM to speed up my program a tad.
Thanks to MiaM and Rob for these interesting ideas.
Until next time…
The array usage of 217 bytes is the entire array. 210 of that is 5 bytes for each value and 7 is the header structure used by the interpreter for bookkeeping.
Also, CLEAR after NEW is unnecessary. NEW already does what a plain CLEAR does.
I have forgotten everything I learned. It sounds like an array does not have very much more overhead beyond that header structure, then?
It would probably be slower using an integer array ( DIM K%(41) ) but would save memory as each entry then only takes 2 instead of 5 bytes.
Btw did you test my “compromise” with one on… goto and one if… then? Probably not worth it.
The problem with erraneous key presses ending up restarting the program (goto 0) can be solved by having a line 0 that checks if a variable isn’t zero, and then jumps to the line after the on… goto line. Anywhere before the on…goto you’d set the variable that line 0 tests. Btw as on…goto don’t jump when the parameter is 0, you could use the same variable as a parameter to om…goto and the if statement at line 0. On the other hand, as an on…goto only needs the keyboard data one time you could save some execution speed and code size by having the PEEK directly in the ON..GOTO statement and not having a temporary variable.
Btw I have to repeat that variables are always faster than constants so you could replace the 17, 39 and 41 in the if..then version with variables that contain those values. IF…THEN is probably still slower but worth a compare.