PowerBASIC Which Construct Is Fastest? |
For a recent game program I needed to adjust the value of a certain variable
(always equal to 1, 2, 4, or 8), as follows:
IF D=1 THEN D=4 IF D=2 THEN D=8 IF D=4 THEN D=1 IF D=8 THEN D=2 |
Of course, the coding as is would fail because if D started out equal
to 1 or 2, if would exit the routine unchanged.
My standard solution for this sort of situation is a tricky but readable Boolean
formula:
D= -(D=4) -2*(D=8) -4*(D=1) -8*(D=2) |
Doubtless most others would prefer something else, which is perfectly fine.
I wondered, though, in just how many different ways the requirement might be
accommodated; and I further wondered which method actually would be the
fastest — not that it would be likely to matter in actual practice.
I came up with twenty-two different methods of processing variable
D in the necessary manner; some are admittedly esoteric, and there
are others. I ran them through one-billion loops each, supplying equal
doses of [1,2,4,8] as starting values for D.
The results are detailed below, arranged by general category yet numbered according to the order of finish in the speed test. The timing for each run, shown in brackets, is the total seconds accrued for the billion loops.
'----- if/then -----
1. [9.00] IF D=1 THEN
D=4
ELSEIF D=4 THEN
D=1
ELSEIF D=2 THEN
D=8
ELSE
D=2
END IF
2. [11.1] IF D=1 OR D=4 THEN D=5-D ELSE D=10-D
3. [14.0] IF D=1 THEN D=4 ELSE IF D=4 THEN D=1 ELSE IF D=2 THEN D=8 ELSE D=2
4. [18.9] IF (D AND 5) THEN D=5-D ELSE D=10-D
'----- structured if -----
5. [24.3] IIF(D=1,4, IIF(D=2,8, IIF(D=4,1, 2)))
6. [26.3] D= IIF((D AND 5), 5-D, 10-D)
7. [28.8] D= IIF(D=1 OR D=4, 5-D, 10-D)
'----- choice -----
8. [32.5] D= SWITCH(D=1,4, D=2,8, D=4,1, D=8,2)
9. [33.0] D= CHOOSE(D,4,8,0,1,0,0,0,2)
10. [39.5] D= CHOOSE(-((D AND 5)=0), 10-D ELSE 5-D)
'----- boolean -----
11. [40.0] D= 5-5*(D=2 OR D=8)-D
13. [46.5] D= -(D=4) -2*(D=8) -4*(D=1) -8*(D=2)
'----- goto -----
12. [46.2] ON D GOTO 1,2,0,4,0,0,0,8
1: D=4: GOTO 0
2: D=8: GOTO 0
4: D=1: GOTO 0
8: D=2:
0:
15. [51.9] ON -(D=1 OR D=4) GOTO 98
D=10-D: GOTO 99
98: D=5-D
99:
'----- array -----
14. [51.9] D=P(D) 'P(1)=4, P(2)=8, P(4)=1, P(8)=2
'----- select -----
16. [65.6] SELECT CASE D
CASE 1,4: D=5-D
CASE 2,8: D=10-D
END SELECT
'----- number sign -----
17. [70.6] D= (2-SGN(D AND 5))*5 -D
'----- logarithm -----
18. [131] IF LOG2(D)/2 = LOG2(D)\2 THEN D=10-D ELSE D=5-D
19. [179] D= 5*(2+(LOG2(D)/2 = LOG2(D)\2)) -D
'----- strings -----
20. [205] D= VAL(MID$("48x1xxx2",D,1))
21. [621] D= INSTR("48x1xxx2",TRIM$(D))
22. [700] D= LEN(EXTRACT$("x48x1xxx2",TRIM$(D)))
Wow! Those speeds are quite a testament to the capabilities of
PowerBASIC, as achieved by my relatively ordinary 3.0 Ghz quad-core
co-processor. It comes as no surprise that the logic functions are
faster than the boolean functions, which are faster than the math functions,
which are far faster than the string functions.
The most concise approach is, as usual, a Boolean — #11.
If you still are programming a Commodore-64, that's the standout choice.
The next most compact options are a SGN function and a CHOOSE
function, neither of which is immediately discernible as to intent.
The most space-consuming method actually won the contest handily, and that
did surprise me; for in the BASIC days of yore, cramming statements onto a logical
line invariably reduced run-time. I had assumed that #3 would
fare better than #1, but it wasn't even close for reasons that escape me.
Note also how much the logical OR in #2 outperformed
the bitwise OR in #4.
Personally, I never would use method #1 — too much wasted space both on
the screen and in the program listing. Although I am wont to stick with a
beloved Boolean despite the loss of a few billionths of a second per iteration,
on this occasion I will opt for the eminently self-explanatory
construct #2.