18. PROGRAM LOOPS Calculations Try to remove all unnecessary calculations from loops, e.g.: FOR i=1 TO 1000 x(i)=2*q*i NEXT i It's a better idea to calculate 2*q outside the loop: q2=q*2 FOR i=1 TO 1000 x(i)=q2*i NEXT i Always try to convert floating point variables to integers before entering a loop. Then you will be able to use the fast integer-operators. An obvious example would be a calculation with dollars (24.37) that could be replaced by a calculation with cents (2437). Use this method if you know the lowest possible value of the floating point variable (0.01 in this case) and then divide by this value. But watch out for rounding errors and integer-overflow. Powers of 2 can be calculated fast by setting a bit: x%=BSET(0,6) ! faster than x%=2^6 And for the ultimate speed-freaks, multiplying with a power of 2 is slightly faster with SHL: y%=SHL(x%,3) ! faster than y%=MUL(x%,8) Of course there is no overflow-control if you use SHL (or MUL). Sometimes, calculations in a loop can be replaced by a look-up table: FOR i=1 TO 1000 y%(i)=x|(i)^2 NEXT i First, create a table of squares: DIM square%(255) FOR i=0 TO 255 square%(i)=i*i NEXT i Then use this table in the loop: FOR i=1 TO 1000 y%(i)=square%(x|(i)) NEXT i FOR ... NEXT I use local variables in Procedures if possible. But if you intend to compile the program later, you could declare the counter in a FOR ... NEXT loop as a global variable. In the compiled program, the loop will be executed slightly faster. The gain in speed is almost negligible, so this is not a good reason to use global variables instead of local variables. If you use floating point count-variables in a FOR ... NEXT loop (or any other loop), you could encounter unexpected problems: FOR i#=0.1 TO 0.9 STEP 0.1 PRINT i# NEXT i# You would expect 0.9 as the result of the last addition (0.8 + 0.1), but 0.9 is never printed! This is not a bug in GFA-Basic, but caused by the internal (binary) representation of floating point numbers. The last addition results in a number slightly larger than 0.9 and therefore the loop is left after printing 0.8 . If you insert the line i#=ROUND(i#,14) in the loop, you can solve this problem. But the best solution is to avoid floating point count-variables in loops. Integer count-variables are much faster. You could easily change the loop into: FOR i&=1 TO 9 PRINT USING "#.#";i&/10 NEXT i& If you use a floating point variable in a REPEAT ... UNTIL loop, you can avoid the rounding error by using the special operator '==', which compares the first 28 bits (roughly 8 decimals): i#=0 REPEAT i#=i#+0.1 PRINT i# UNTIL i#==0.9 But you can't use the '=='-operator in a FOR ... NEXT loop. In the following three examples a byte-variable is used as the counter: FOR i|=5 DOWNTO -1 PRINT i| NEXT i| ' FOR i|=250 TO 256 PRINT i| NEXT i| ' FOR i|=255 DOWNTO 0 PRINT i| NEXT i| Of course, a byte-variable cannot have a value of -1 or 256. GFA does not abort with an error-message, but skips the first two loops. Not a true bug perhaps, but close. The third case is different, there we enter an endless loop. That's because the counter becomes -1 after the last step, and that is seen as 255 through the byte-spectacles of the loop so we start all over again. You should realize that the FOR ... NEXT counter is always increased/decreased (with TO/DOWNTO) with one before leaving the loop: FOR i&=1 TO 100 ' Never mind this line NEXT i& PRINT i& ! i& is now 101, not 100 If the user should be able toa bort a long FOR ... NEXT loop prematurely, you could use EXIT IF: FOR i%=1 TO 100000 (...) EXIT IF INKEY$=CHR$(27) ! user pressed NEXT i% Loops Although you can use many different loops in GFA-Basic 3.0, there are basically only two varieties. You can first test a condition, and then either continue or leave the loop. Or you can first enter the loop, and then test a condition to decide if you are going to continue or leave. In an interpreted program the first choice is the fast FOR ... NEXT loop, then the (slower) REPEAT ... UNTIL loop and finally the (slowest) WHILE ... WEND loop. In a compiled program all loops are executed equally fast! If you use a DO ... LOOP, an EXIT IF condition will always take some extra time. Try to avoid a negative test in a loop, as it will take more time to evaluate this. E.g. replace: WHILE NOT condition! (...) WEND by the much faster: DO UNTIL condition! (...) LOOP Or similarly replace: REPEAT (...) UNTIL NOT condition! by the faster: DO (...) LOOP WHILE condition! Finally, you could combine the test of one condition at the start of the loop with the test of another condition at the end of the loop: DO UNTIL condition_1! (...) LOOP WHILE condition_2!