Question re how if .. elseif .. endif works

wapo54001

Senior Member
Ah, never mind, I think I found that once it executes one section it jumps to the endif.



I am not sure what happens when doing math in an if...elseif....endif routine.

Let's say a variable w1 is tested and meets the > 1004 test. If, in the math that is then executed, w1 now meets the test of range 2, 3, or 4, will that choice also be executed, or once it has met one test does it jump to the end of the routine?

I would like to use the same word variable throughout this test due to space constraints. If I have to, I can change the math line to a different variable to house the result so that w1 does not change during execution of this routine.



Code:
'Range1
	if w1 > 1004 then			
	w1 = w1 * 12 / 17 - 45
'Range2
	elseif w1 > 725 and w1 < 1005 then				
	w1 = w1 * 5 / 47 + w1 - 447			
'Range3
	elseif w1 > 474 and w1 < 726 then	
	w1 = w1 * 25 / 41 - 86
'Range4
	elseif w1 < 475 then						
	w1 = w1 * 26 / 67 + 19
	endif
endif
 
Last edited:

hippy

Ex-Staff (retired)
If the test is matched it will do the 'then' action otherwise it will do the 'else' or 'elseif' option.
 

BCJKiwi

Senior Member
The logic test occurs on the else or elseif line.
If the logic is satisfied (e.g. w1 > 1004), then all the following code up to the next elseif is processed then it jumps to the endif.

The code you posted is actually not correct as it has 2 endifs for one logical construct ( else .. elseif... elseif... endif)

should be;
Code:
'Range1
    if w1 > 1004 then            
    w1 = w1 * 12 / 17 - 45
'Range2
    elseif w1 > 725 and w1 < 1005 then                
    w1 = w1 * 5 / 47 + w1 - 447            
'Range3
    elseif w1 > 474 and w1 < 726 then    
    w1 = w1 * 25 / 41 - 86
'Range4
    elseif w1 < 475 then                        
    w1 = w1 * 26 / 67 + 19
    endif
For every if there should be and endif. Elseif should be thought of as another type of if.
 

Texy

Senior Member
In some scenarios you might also like to consider the Select Case statement,
which can make things look clearer.
Manual 2 page 139


Texy
 

wapo54001

Senior Member
BCJ,

The code was snipped from a longer program, and the extra endif got left in by mistake; I didn't notice it because that was not the focus of my question.

Texy,

My program uses 255 bytes of 256 available. The select case uses more code space than if .. elseif .. endif does. I tried it and rejected it at an earlier stage. If you search the archives, you will find a thread where we discussed the most effective code for making such selections.

Actually, in many cases you can save code space by using multiple discrete if .. endif arguements instead of a single multiple ... elseif ... elseif routine.
 
Last edited:

hippy

Ex-Staff (retired)
If you need to minimise code spcae it may be better to leave out all IF-THEN and IF-ELSEIF entirely and go back to the IF-THEN-label. Not as elegant to read but that'sthe price to pay. You could put that code in a subroutine and use RETURN to fall out to save an extra byte or so ...

Code:
Range1:
    if w1 <= 1003 then Range2            
    w1 = w1 * 12 / 17 - 45
    return
Range2:
    if w1 <= 725 or w1 >= 1005 then Range3                
    w1 = w1 * 5 / 47 + w1 - 447            
    return
Range3:
    elseif w1 <= 474 or w1 >= 726 then Range4    
    w1 = w1 * 25 / 41 - 86
    return
Range4:
    [i]etc[/i]
 

wapo54001

Senior Member
hippy,

At first blush your code saves 9 bytes over mine. I'll go over it in detail and make sure the bases are covered.

Thanks.
 

wapo54001

Senior Member
Hippy, I'm not sure how this works. Consider the following:
Code:
'Range select

if w1 > 1004 then range1:
if w1 > 725 and w1 < 1005 then range2:
if w1 > 474 and w1 < 726 then range3
if w1 < 475 then range4:

Range1:
    w1 = w1 * 12 / 17 - 45
    return
Range2:
    w1 = w1 * 5 / 47 + w1 - 447            
    return
Range3:
    w1 = w1 * 25 / 41 - 86
    return
Range4:
   w1 = w1 * 26 / 67 + 19
   return
How do you get the code to skip remaining options and still keep the byte count to a minimum? The problem is that since w1 is changed by the math, it might be true again down the list.

Let's say that w1 = 1005 so Range1 is true. The program jumps to Range1 and executes the code, which is a computation of w1 that changes w1's value so that Range2 becomes true and the Range2 computation takes place. How do you get the code to skip the remaining "if w1" tests so that this is not a problem?
 

boriz

Senior Member
This might work:
Code:
select w1
	case >1004 : w1 = w1 * 12 / 17 - 45
	case >725 : w1 = w1 * 5 / 47 + w1 - 447
	case >474 : w1 = w1 * 25 / 41 - 86
	else : w1 = w1 * 26 / 67 + 19
endselect
When it finds a Case that it likes, it skips the rest.
 

wapo54001

Senior Member
Hippy, -- oops, make that boriz.

I have never looked at that command before; it looks promising but I'll need to see how many bytes it consumes. I've learned that short text doesn't necessarily mean short code into the chip!
 
Last edited:

moxhamj

New Member
I've never coded like this where the answer to the first test is then potentially tested again further down. Boriz - is that code tested? It looks neat, but I'm thinking it could compile either way and w1 could get tested several times. Or worse, get tested sometimes but not others depending on the value, giving an intermittent bug.

Usual practice would be to make the answer w2 rather than w1. Is it code space or number of variables that is the problem. If the latter, you can always do a poke of a variable at the beginning into scratchpad ram, then peek it out at the end.

Another answer could be multiple goto's. Many years ago, goto became unfashionable, but I remember reading (and then using) some very nifty code for a quicksort where the author justified the use of goto on philosophical grounds, and then backed it up with some very fast code. Goto works because it translates to a jump in machine code which is just one instruction. So if you do the first test, you jump somewhere else, do the sum using the same variable, then jump to the end, and you can be quite definite about where the program path is going.
 

hippy

Ex-Staff (retired)
Hippy, I'm not sure how this works. Consider the following: ... How do you get the code to skip remaining options and still keep the byte count to a minimum? The problem is that since w1 is changed by the math, it might be true again down the list.
After one of the options has executed it executes a return, thus it's impossible for others to be executed.
 

moxhamj

New Member
Re Hippy's code in post #6, that will work but I think there is a line missing in the code which is inferred in the text, and that is a

gosub range1

at the beginning.

The code then falls out of the gosub in multiple places with many returns. But it only ever falls out of the gosub once, so only one test is executed.

After 'etc' there would also need to be a return to catch any leftover conditions.

I'm not sure how picaxe machine code compiles, but certainly in z80 machine code, a return is even faster than a jump. (a return is a one byte instruction that pops the return location off the stack, wheras a jump is a 2 or 3 byte instruction because it has to have a value to indicate it is a jump and also some bytes to say where to jump to).
 
Last edited:

hippy

Ex-Staff (retired)
You got it right Dr_Acula. In this case RETURN is shorter than GOTO so even with the GOSUB overhead this saves code space. For the PICAXE it will be slower but it's the never ending trade-off between code space and speed. It's one or the other.
 

wapo54001

Senior Member
I used the method suggested by boriz in post #9 in two places in my code and saved a whopping 20 bytes, down to 235 from 255 of 256 bytes available.
It looks like it will work, but will verify at the bench later.

A substantial part of the savings was to go from specifying a range of values per case to specifying only a maximum or minimum value per case and using the adjoining case to specify the other value.

This will allow me to do more with the newly available code space.
 

wapo54001

Senior Member
I've never coded like this where the answer to the first test is then potentially tested again further down. Boriz - is that code tested? It looks neat, but I'm thinking it could compile either way and w1 could get tested several times. Or worse, get tested sometimes but not others depending on the value, giving an intermittent bug.
Dr. Acula, what did you mean by "it could compile either way"?
 
Top