See also: part 1.
“Let’s build a worksheet to calculate these values.”
This is a quote that will stay with me. It comes from a video response from Paul Fiscarelli that demonstrates his solution for adding gravity to the bouncing ball demo. He suggests pre-calculating the positions so nothing has to be calculated at run-time.
In part 3 of my bouncing ball series, I discussed the idea of using DATA for the positions rather than doing math simply because it would be faster. But, the math still has to be done somewhere to generate the values for those DATA statements.
But math is hard.
Fortunately, Paul provides the math.
And, he does it with style, using real equations that calculate an object in free-fall. Impressive! His video explains how the formulas work, and then he uses an Excel spreadsheet to do all the math, and then fills it up with locations representing each Y position of the ball, all designed to perfectly fit the 32 column screen. That’s something my brute-force simulated gravity attempt did not do.
He then uses some fancy Excel formulas to make it generate all the data together as numbers separated by commas, ready to be copy-and-pasted into an editor with the rest of the BASIC program.
Well done, Paul! I’m impressed!
Your demo sent me back to my benchmarking to find out which was faster:
Array or DATA?
Paul’s recalculated data is stored in DATA statements, such as:
During the initialization code, he loads the data up in an array, such as:
FOR I=0 TO 20:READ Y(I):NEXT
He then has all his Y positions available just by using an index counter (he re-purposes my YM Y-movement variable) that loops through them. In his example, he places a -1 at the end of the DATA statement, and uses that as a dynamic way to indicate the end of the data. When he’s retrieving his Y value from the array, he checks for that to know when he needs to start back at the beginning of the array:
YM=YM+1:Y=Y(YM):IF Y<0 THEN YM=0:Y=Y(YM)
In part 8 of my Optimizing Color BASIC series, I looked into arrays and discovered they were significantly slower than non-array variables. Surely an array is faster than the calculating that gravity equation real-time, but it it faster than just READing each item each time?
READ/RESTORE versus Arrays
I present a new benchmark… which is faster? Using READ/RESTORE, or using pre-loaded arrays? Let’s fine out!
First, the test program is going to load 20 values into an array, then in the benchmark loop it’s going to just assign the next array value to a variable and increment an index variable until it gets to the end of the data. It will then reset the index to 0 and start over. This is a scaled-down version of Paul’s demo looping through the array values.
0 REM ARRAYS.BAS 6 DIMZ(20),Y,X:FORA=0TO19:READZ(A):NEXT:X=0 5 DIM TE,TM,B,A,TT 10 FORA=0TO3:TIMER=0:TM=TIMER 20 FORB=0TO1000 40 Y=Z(X):X=X+&H1:IFX>&H14 THENX=0:GOTO40 70 NEXT 80 TE=TIMER-TM:PRINTA,TE 90 TT=TT+TE:NEXT:PRINTTT/A/60:END 100 DATA 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,-1
Running this in the Xroar emulator gives 12.65 seconds.
Next I removed the array and just do a READ each time, looking for a -1 which indicates we need to RESTORE back to the start of the data. It looks like this:
0 REM RESTORE.BAS 5 DIM TE,TM,B,A,TT 10 FORA=0TO3:TIMER=0:TM=TIMER 20 FORB=0TO1000 30 READ Z:IFZ=-1THENRESTORE:GOTO30 40 Y=Z 70 NEXT 80 TE=TIMER-TM:PRINTA,TE 90 TT=TT+TE:NEXT:PRINTTT/A/60:END 100 DATA 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,-1
This produces 10.51 seconds! A bit faster. But it’s not quite the same.
In the READ/RESTORE example, I have to keep checking for -1. In the array version, there is an index value (needed for the array) that can be checked. Is it faster to do that, rather than looking for -1?
0 REM RESTIDX.BAS 5 DIM TE,TM,B,A,TT 10 FORA=0TO3:TIMER=0:TM=TIMER 20 FORB=0TO1000 30 READ Z:X=X+&H1:IFX>&H14 THENRESTORE:X=&H0:GOTO30 40 Y=Z 70 NEXT 80 TE=TIMER-TM:PRINTA,TE 90 TT=TT+TE:NEXT:PRINTTT/A/60:END 100 DATA 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,-1
Yipes! The one slows down to 14.15 seconds. It seems incrementing a variable, comparing it, then resetting it adds a lot of overhead. It seems just checking for -1 is the faster way.
Let’s make it a tad bit faster.
In part 6 of my BASIC series, I looked at using READ on integers, hex, and strings. I found HEX to be almost twice as fast. I’ll also replace the -1 with some HEX value we won’t be using. Let’s try that here:
0 REM DATAHEX.BAS 10 FORA=0TO3:TIMER=0:TM=TIMER 20 FORB=0TO1000 30 READ Z:IFZ=&HFF THENRESTORE:GOTO30 40 Y=Z 70 NEXT 80 TE=TIMER-TM:PRINTA,TE 90 TT=TT+TE:NEXT:PRINTTT/A/60:END 100 DATA &1,&H2,&H3,&H4,&H5,&H6,&H7,&H8,&H9,&HA,&HB,&HC,&HD,&HE,&HF,&H10,&H11,&H12,&H13,&H14,&HFF
It looks like using Paul’s technique to pre-calculate all the gravity values, and then reading them dynamically from DATA statements in the demo, should give us a great speed boost even over my simple attempt to do things like “Y=Y+.25”.
Thanks, Paul, for providing us with a way to do great “real” gravity without having to do a bit of math…on the CoCo. Hopefully I can dissect those equations and replicate it.
This is the first time I have ever enjoyed watching a presentation on Excel. I hope you enjoy it, too. Here’s Paul’s video:
Until next time…