Tokenization question: IF/ELSE vs multiple IF statements

chipwich

Member
This code tokenizes to 26 bytes
Code:
if b1=0 then
	pause 5
elseif b1=1 then
	pause 10
elseif b1=2 then
	pause 20
endif
whereas the following code tokenizes to 21 bytes
Code:
if b1=0 then
	pause 5
endif
if b1=1 then
	pause 10
endif
if b1=2 then
	pause 20
endif

What the difference in tokenization that is responsible for the size difference? Can someone offer insight on the size/performance optimization tradeoffs between these 2 coding methods? Thanks in advance.
 

westaust55

Moderator
The use of the ELSEIF may gain some speed improvement as once a test has succeeded there is no need to to continue performing the remaining IF b0 = ?? THEN tests.

Try putting these in a FOR...NEXT loop running 10,000 times and check the timing.
Might then also be worth examining the SELECT...CASE and see what space and timing that needs.
 

inglewoodpete

Senior Member
PE Only

The If/ElseIf/Else/EndIf structure was introduced in PE Version 5. It was purely a compiler upgrade, so there were no added features in the chips themselves. (This may have changed since 2006: there is no way of telling.)

So any of the 'new' structures Eg If/ElseIf/Else/EndIf; Select Case and Do/Loop are a software-only addition to the basic capability (If/Then/GoTo/GoSub) of the PICAXE. By my way of thinking the newer code-structure features, if anything, will add to the overheads of the tokens and execution speed.

On the other hand, the chips are now offered with more/faster speed options and more program space. This more than compensates for the overheads created by providing the ability to use better programming structures.

I have found that, when I have to squeeze the last drop of speed out of a PICAXE, additional labels and use of the dreaded GoTo command is the only way to do it. (Its a personal thing but I have an allergic reaction to the GoTo command :).)
 

westaust55

Moderator
A few tests demonstrate the real position in terms of program speed with the use of the IF…THEN…ELSEIF…ENDIF structure.

Using a 40X1 running at 4 MHz as the test bench and performing the desired program structure 10,000 times the results are as below.
The empty FOR,,,NEXT loop takes 12 seconds to complete so this time is deducted from the overall times to ascertain the duration for the actual code under test:

With the code:
Code:
if b1=0 then
	; pause 5
elseif b1=1 then
	; pause 10
elseif b1=2 then
	; pause 20
endif
b1 = 0 ==> 11 seconds
b1 = 1 ==> 18 seconds
b1 = 2 ==> 23 seconds
So clearly there is an early exit occurring once a match has occurred in an IF…THEN test.

With the code:
Code:
if b1=0 then
	; pause 5
endif
if b1=1 then
	; pause 10
endif
if b1=2 then
	; pause 20
endif
The duration is 21 seconds irrespective of b1 = 0, 1 or 2.
So great where consistent timing is required.

With the code:
Code:
Select b1
Case 0
	; pause 5
Case 1
	; pause 10
Case 2
	; pause 20
Endselect
[/code]

b1 = 0 ==> 11 seconds
b1 = 1 ==> 21 seconds
b1 = 2 ==> 23 seconds

So, using the SELECT…CASE is slightly worse as there are more cases and potentially slower for cases further down the list.

With the code:
Code:
Lookup b1, (5,10,20),b2
The duration is 10 seconds irrespective of b1 = 0, 1 or 2.
So great where consistent timing is required and slightly faster, at least for smaller numbers of entries.
 

hippy

Technical Support
Staff member
What the difference in tokenization that is responsible for the size difference?
The difference is that, in the IF-ELSEIF case, all subsequent IF comparisons are jumped over once a condition has been met. In the second, all IF comparisons will be tested every time.

You can turn your second code into the first with the addition of GOTO commands ...

Code:
if b1=0 then
	pause 5
	[b]goto done[/b]
endif
if b1=1 then
	pause 10
	[b]goto done[/b]
endif
if b1=2 then
	pause 20
endif
[b]done:[/b]
That adds extra program code used but the average execution speed is lowered.

The PICAXE firmware only understands "IF condition THEN label" so all high level block constructs, IF-ELSE, IF-ELSEIF, SELECT-CASE and DO-LOOP, are translated to appropriate sequences of IF-THEN and GOTO commands. Sometimes it can be better to do things mathematically -

b2 = b1 * 5 + 5
Pause b2

Or the LOOKUP westaust55 suggests.
 

Buzby

Senior Member
...
b2 = b1 + 1 * 5
Pause b2
b1 = 0, b2 = 0 + 1 * 5, b2 = 5, Correct
b1 = 1, b2 = 1 + 1 * 5, b2 = 10, Correct
b1 = 2, b2 = 2 + 1 * 5, b2 = 15, Wrong, the pause is 20, not 15.

Or am I missing something ?
 

Hemi345

Senior Member
I've found SELECT/CASE to use quite a few more bytes of program space compared to IF/ELSEIF. So it seems SELECT/CASE is only beneficial, IMO, for being easy to follow/read while programming.
 

chipwich

Member
Much thanks for the excellent explanations. With today's PCs having GB of memory and GHz processors, speed/size optimizations don't get nearly the attention that they previously did, so it's fun to revisit this.

btw, seeing how my sample code snippet was too easily improved, I'll try to be more challenging next time.

Something like:

Code:
if b1=0 then
	pause 3
endif
if b1=1 then
	pause 4
endif
if b1=2 then
	pause 7
endif
if b1=3 then
	pause 11
endif

:cool:
 

westaust55

Moderator
Lookup b1, (3,4,7,11),b2
Pause b2

If corruption of b1 is allowed then replace b2 with b1


but that is a version of the Fibonacci Series called the Lucas Series : 2,1,3,4,7,11,18,29, . . .

2 + 1 = 3
1 + 3 = 4
3 + 4 = 7
4 + 7 = 11
7 + 11 = 18
11 + 18 = 29, etc


Clunky but this would work:
Code:
for delay = 0 to b1
  new = root+old
  root = old
  old = new
next
pause new

But since your sequence selection suggests you know about such sequences, I leave it to you show us your new found skills and how you might compute this more efficiently ;)
 
Last edited:
Top