Page 1 of 2

ProcedureReturn optimisation?

Posted: Sun Jun 10, 2007 11:01 am
by PB
Which code block below is better to use, when considering final exe size and
speed of the procedure? I'd say the second is better due to far less code, but
it also creates a new variable (r), so how can I know for sure? Thanks.

Code: Select all

Procedure IsNumberLessThan100(n)
  If n<100
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
EndProcedure

Debug IsNumberLessThan100(50)

Code: Select all

Procedure IsNumberLessThan100(n)
  If n<100 : r=1 : EndIf
  ProcedureReturn r
EndProcedure

Debug IsNumberLessThan100(50)

Posted: Sun Jun 10, 2007 11:21 am
by Trond
The first one is much faster.

This one is just as fast as the first one, but smaller:

Code: Select all

Procedure IsNumberLessThan1002(n) 
  If n < 100
    ProcedureReturn 1
  EndIf
  ProcedureReturn 0
EndProcedure
Also take into account whether the majority of numbers are less than 100. If the majority is 100 or more, then this is much faster because the forward jump isn't taken:

Code: Select all

Procedure IsNumberLessThan1002(n) 
  If n >= 100
    ProcedureReturn 0
  EndIf
  ProcedureReturn 1
EndProcedure

Posted: Sun Jun 10, 2007 11:24 am
by PB
Okay, the reason I asked is because I read somewhere once that a procedure
should only ever have 1 x ProcedureReturn, and I loaded one of my old sources
and saw 2 x ProcedureReturns in there, and wondered if it was worth changing
it to only one, like in my code examples in this topic. Any ideas on this?

Posted: Sun Jun 10, 2007 11:25 am
by Trond
Don't change it. Only 1 procedurereturn is only recommended for readability, it is always slower.

Posted: Sun Jun 10, 2007 11:40 am
by maw
This is how I do it:

Code: Select all

Procedure.l IsNumberLessThan100(n)
  If n<100
    ProcedureReturn #True
  EndIf
EndProcedure

Debug IsNumberLessThan100(50)
Letting the procedure return naturally without ProcedureReturn returns #False, has worked in all versions so far, though I'm not sure this can be counted on in the future? Fred/Freak?

Not sure if it's shorter or faster, but personally I prefer it with only one ProcedureReturn.

Posted: Sun Jun 10, 2007 11:51 am
by Trond
Yes, that's shorter and faster and should be reliable for future versions as well.

Posted: Sun Jun 10, 2007 12:08 pm
by Derek
Why doesn't this work then?

Code: Select all

Procedure.l IsNumberLessThan100(n) 
  ProcedureReturn n<100
EndProcedure 

Debug IsNumberLessThan100(50)
Debug 50<100
Debug 101<100
It does in the debug lines!

Posted: Sun Jun 10, 2007 12:18 pm
by Trond
manual

Posted: Sun Jun 10, 2007 12:47 pm
by Derek
If you mean that in the manual it says procedurereturn with a value then why doesn't this work?

Code: Select all

Procedure.l IsNumberLessThan100(n) 
  a=n<100
  ProcedureReturn a 
EndProcedure 

Debug IsNumberLessThan100(50) 
Debug 50<100 
Debug 101<100
Also according to the manual, 'Debug - The expression can be any valid PureBasic expression, from numeric to string.'

So in the above 50<100 must be valid, therefore a=n<100 should be valid, procedurereturn a should be valid so the program should work.

I know it might be considered a boolean result and they are not implemented but in that case why does the debug command work?

Posted: Sun Jun 10, 2007 2:08 pm
by jear
Why not Macro Is()?

Code: Select all

Procedure.l IsNumberLessThan100_0(n.l) 
  If n<100
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
EndProcedure

Procedure.l IsNumberLessThan100_1(n.l) 
  If n<100 : ProcedureReturn #True : EndIf 
EndProcedure

Procedure.l IsNumberLessThan100_2(n.l) 
  ProcedureReturn (n<100) Or #False
EndProcedure 

Macro Is(expression)
  expression Or #False
EndMacro

Dim num.l(1000000) : For ix.l = 0 To 999999 : num(ix) = Random(200) : Next

time.l = ElapsedMilliseconds()
For ix.l = 0 To 999999
  a.l = IsNumberLessThan100_0(num(ix)) 
Next
Debug ElapsedMilliseconds() - time

time = ElapsedMilliseconds()
For ix = 0 To 999999
  a = IsNumberLessThan100_1(num(ix)) 
Next
Debug ElapsedMilliseconds() - time

time = ElapsedMilliseconds()
For ix = 0 To 999999
  a = IsNumberLessThan100_2(num(ix)) 
Next
Debug ElapsedMilliseconds() - time

time = ElapsedMilliseconds()
For ix = 0 To 999999
  a = Is(num(ix) < 100) 
Next
Debug ElapsedMilliseconds() - time

Posted: Sun Jun 10, 2007 2:27 pm
by Trond
I know it might be considered a boolean result and they are not implemented but in that case why does the debug command work?
Pure luck.

Posted: Sun Jun 10, 2007 2:38 pm
by Derek
Trond wrote:Pure luck.
Ah right, I thought it might be something technical like that.

Posted: Sun Jun 10, 2007 3:45 pm
by Demivec
jear wrote:Why not Macro Is()?
When you rerun your code sample without debugger and boosting the # of tests 10x you'll see the PB's first example(IsNumberLessThan100_0) is the fastest everytime. It's about twice as fast as Macro Is().

Code: Select all

Procedure.l IsNumberLessThan100_0(n.l)
  If n<100
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
EndProcedure

Procedure.l IsNumberLessThan100_1(n.l)
  If n<100 : ProcedureReturn #True : EndIf
EndProcedure

Procedure.l IsNumberLessThan100_2(n.l)
  ProcedureReturn (n<100) Or #False
EndProcedure

Macro Is(expression)
  expression Or #False
EndMacro

Dim num.l(10000000) : For IX.l = 0 To 9999999 : num(IX) = Random(200) : Next

time.l = ElapsedMilliseconds()
For IX.l = 0 To 9999999
  a.l = IsNumberLessThan100_0(num(IX))
Next
b.l=ElapsedMilliseconds() - time
MessageRequester("",Str(b))

time = ElapsedMilliseconds()
For IX = 0 To 9999999
  a = IsNumberLessThan100_1(num(IX))
Next
b.l=ElapsedMilliseconds() - time
MessageRequester("",Str(b))

time = ElapsedMilliseconds()
For IX = 0 To 9999999
  a = IsNumberLessThan100_2(num(IX))
Next
b.l=ElapsedMilliseconds() - time
MessageRequester("",Str(b))

time = ElapsedMilliseconds()
For IX = 0 To 9999999
  a = Is(num(IX) < 100)
Next
b.l=ElapsedMilliseconds() - time
MessageRequester("",Str(b))

Posted: Sun Jun 10, 2007 3:52 pm
by maw
Demivec wrote:When you rerun your code sample without debugger and boosting the # of tests 10x you'll see the PB's first example(IsNumberLessThan100_0) is the fastest everytime. It's about twice as fast as Macro Is().
Not here.. I get 110, 110, 110, 110.. And sometimes 109 or 111 on some of them..

With Core2Duo E6600, 2.4GHz, running Vista x64.

Posted: Sun Jun 10, 2007 4:08 pm
by Demivec
@maw: I'm running with an AMD athlon 64 at 2.2Ghz, running XP. Which might explain the differences. I apologize for ommiting that.

When I change the line with the test data from

Code: Select all

Dim num.l(10000000) : For IX.l = 0 To 9999999 : num(IX) = Random(200) : Next
to

Code: Select all

Dim num.l(10000000) : For IX.l = 0 To 9999999 : num(IX) = Random(99) : Next
and alternatively

Code: Select all

Dim num.l(10000000) : For IX.l = 0 To 9999999 : num(IX) = Random(200)+101 : Next
or simply put make the values all greater than 100 or all less than 100 I get a definate win for the first routine for speed in both cases.

My #'s are (125, 218, 375, 250) for the test as is.