"Internet is so huge and pointless that for some people it is a
complete substitute for life."
YOUR SECOND GFA BASIC 3.XX MANUAL
- or -
HOW I LEARNED TO STOP WORRYING AND LOVE GFA-BASIC
PART 19
CHAPTER EIGHTEEN - PROGRAM LOOPS
by Han Kempen
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 <Esc>
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!
Disclaimer
The text of the articles is identical to the originals like they appeared
in old ST NEWS issues. Please take into consideration that the author(s)
was (were) a lot younger and less responsible back then. So bad jokes,
bad English, youthful arrogance, insults, bravura, over-crediting and
tastelessness should be taken with at least a grain of salt. Any contact
and/or payment information, as well as deadlines/release dates of any
kind should be regarded as outdated. Due to the fact that these pages are
not actually contained in an Atari executable here, references to scroll
texts, featured demo screens and hidden articles may also be irrelevant.