- The classic one is to use DEFINT A-Z. This forces you to use
as many integer variables as possible.
- Use integer variables to index FOR loops. This may require
substitution and algebraic simplification.
Before:
FOR i!=0 to 0.3 STEP 0.01
p!=i!*3
NEXT
After:
FOR i%=0 to 30
p!=i%*0.03
NEXT
- Use SELECT CASE instead of a bunch of ELSEIFs.
Before:
IF i=1 THEN
CALL DrawSprite
ELSEIF i=6 THEN
CALL PlaySound
ELSEIF i>9 AND i<16 THEN
CALL Calculate(i)
ELSE
PRINT "."
ENDIF
After:
SELECT CASE i
CASE 1
CALL DrawSprite
CASE 6
CALL PlaySound
CASE 10 TO 15
CALL Calculate(i)
CASE ELSE
PRINT "."
END SELECT
- If your code has a lot of floating point calculations that need
high accuracy, compile with QB 4.0. (e.g. a raytracer)
- If your code has a lot of floating point calculations that don't
need more than 8 bits of accuracy, then definitely convert it to fixed
point. Even if it needs up to 16 bits of accuracy, it might be worth
converting to fixed point, if it is being used in the main loop. (e.g. a rotozoomer or voxel terrain)
- don't use IFs (conditional branches). Some comparison results
can be directly be used in a calculation. Note that in QB,
a TRUE boolean expression equals -1, and a FALSE one equals 0.
Before:
IF a>4 THEN
b=5
ELSE
b=0
ENDIF
After:
b=-5*(a>4)
- use an assembler keyboard handler or INP(&H60) plus keyboard buffer
clearing routines instead of INKEY$.
- store the results of complicated expressions in look-up tables.
Before:
pi=ATN(1)*4
DO
FOR i=0 to 360
x!=100+COS(i*pi/180!)
y!=100+SIN(i*pi/180!)
PSET(x!,y!),c
NEXT i
LOOP until LEN(INKEY$)
After:
pi=ATN(1)*4
- Make constants CONST. Unfortunately, you can't use transcendental
functions like ATN on the right side anymore.
Before:
pi=ATN(1)*4
piover2=pi/2
After:
CONST pi=3.14159265358979#
CONST piover2=pi/2
- Unroll short loops.
Before:
FOR a=1 to 8
POKE(a,0),a
NEXT
After:
POKE 1,1
POKE 2,2
POKE 3,3
POKE 4,4
POKE 5,5
POKE 6,6
POKE 7,7
POKE 8,8
- Partially unroll long loops.
Before:
FOR x=0 TO 319
POKE x,a
NEXT
After:
' this is a silly example, you should be using
' MMX filling or REP STOSB at least.
FOR x=0 TO 319 STEP 4
POKE x,a
POKE x+1,a
POKE x+2,a
POKE x+3,a
NEXT x
- Move junk outside of the inner loops (code movement).
Before:
FOR y=0 TO 199
FOR x=0 TO 319
a=x*4+COS(t)
b=y*3+SIN(t)
NEXT
NEXT
After:
FOR y=0 TO 199
b=y*3+SIN(t)
FOR x=0 TO 319
a=x*4+COS(t)
NEXT
NEXT
- Use cache sensitive programming. This means, try to
access your arrays in a sequential manner if possible. If not, access them
in small blocks that are adjacent to eachother.
For example, QB arrays are usually stored in a column major
order.
- Pass dummy parameters to functions to improve alignment. This only makes
a slight difference in speed.
- Prefer array indexing over user defined TYPEs.
Warning: This makes code unreadable.
- Avoid multidimensional arrays.
- Use POKE instead of PSET. This is a simple way to get 2x performance in graphics intensive apps.
- PEEKing from video memory is slower than PEEKing from system memory.
Therefore, use double buffering when you need to do feedback effects.
- Use DEF SEG sparingly.
- Don't use '$DYNAMIC. QB arrays in the default segment are accessed at blazing speed, because
there is no segment switching. However, '$DYNAMIC puts them in different
segments, which need extra instructions to accessed, slowing them down.
This makes a big difference in programs that use large lookup tables in
their inner loop.
- Don't put the main loop in the main code-- put it in a SUB.
- Use AND instead of MOD for MODing by a power of 2.
Before:
a=b MOD 64
After:
a=b AND 63
- Simplify compares against zero.
Before:
' assuming a% only decrements by one
IF a%>0 THEN
b%=b%-1
END IF
After:
IF a% THEN 'note >0 is gone
b%=b%-1
END IF