Petey 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:


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 but 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.

PowerBASIC Menu