Max() and Min(), procedure and macro variants.
Posted: Tue Jul 10, 2007 2:52 pm
If you are unsure which one of the below implementations to use then use either the Max5() and Min5() ones for maximum flexibility. (integers and floats)
Or the inline "if" method examples, for when you really need hardcore speed routines.
I needed this code myself but found it interesting enough to post here.
Something odd here though, the Macro despite being larger in number of instructions, it is faster than the procedure.
I assume the main difference in speed is the call overhead of the procedures.
Another interesting thing is compiling this code with the debugger on or off.
(leave the DisableDebugger in the source, if not it'll take ages)
It seems that if you choose "Compile with debugger" in the IDE menu the result is smaller (i.e. faster) that can't be right can it? *laughs*
I'm also curious if anyone can improve the macro's or the procedures to gain even more speed.
EDIT: Updated to work with Purebasic 5.10
Or the inline "if" method examples, for when you really need hardcore speed routines.
I needed this code myself but found it interesting enough to post here.
Something odd here though, the Macro despite being larger in number of instructions, it is faster than the procedure.
I assume the main difference in speed is the call overhead of the procedures.
Another interesting thing is compiling this code with the debugger on or off.
(leave the DisableDebugger in the source, if not it'll take ages)
It seems that if you choose "Compile with debugger" in the IDE menu the result is smaller (i.e. faster) that can't be right can it? *laughs*
I'm also curious if anyone can improve the macro's or the procedures to gain even more speed.
Code: Select all
;Public Domain
DisableDebugger
EnableExplicit
;Max5() and Min5() should handle any value, with floats be aware of rounding errors. PB 5.10 update by Demivec
Macro Min5(a,b)
(Bool((a)<=(b)) * (a) + Bool((b)<(a)) * (b))
EndMacro
Macro Max5(a,b)
(Bool((a)>=(b)) * (a) + Bool((b)>(a)) * (b))
EndMacro
;Max4() and Min4() are single float only, change .f to .d for doubles.
;Note! It is possible to use integers as output and cast the result back to integer,
;just beware of potential rounding errors and float number ranges. doubles are more flexible.
Procedure.f Min4(a.f,b.f)
If a<b
ProcedureReturn a
EndIf
ProcedureReturn b
EndProcedure
Procedure.f Max4(a.f,b.f)
If a>b
ProcedureReturn a
EndIf
ProcedureReturn b
EndProcedure
;Max3() and Min3() should handle any integer.
;Max3() and Min3() created by technicorn (see post further down)
Macro Min3(a,b)
((Bool((a)<=(b))-1)&(b))|((Bool((b)<(a))-1)&(a))
EndMacro
Macro Max3(a,b)
((Bool((a)>=(b))-1)&(b))|((Bool((b)>=(a))-1)&(a))
EndMacro
;Max2() and Min2() are longs only, change .l to .b or .w or .q for other integers.
Procedure.l Min2(a.l,b.l)
If a<b
ProcedureReturn a
EndIf
ProcedureReturn b
EndProcedure
Procedure.l Max2(a.l,b.l)
If a>b
ProcedureReturn a
EndIf
ProcedureReturn b
EndProcedure
;Max() and Min() should handle any integer.
Macro Min1(a,b)
(Bool((a)>(b))*(b))|(Bool((b)>(a))*(a))
EndMacro
Macro Max1(a,b)
(Bool((a)<(b))*(b))|(Bool((b)<(a))*(a))
EndMacro
timeBeginPeriod_(1)
Define start.l,stop.l,a.l,b.l,n.l,x.l,y.l,text$,c.f,d.f,cc.d,dd.d,z1.f,z2.f,zz1.d,zz2.d
a.l=20
b.l=15
c.f=20.5
d.f=14.8
cc.d=19.9
dd.d=9.3
n.l=0
start=timeGetTime_()
For n=1 To 100000000
x=Max1(a,b)
y=Min1(a,b)
Next
stop=timeGetTime_()
text$+"Max1()/Min1(): "+Str(stop-start)+"ms"+#LF$
n.l=0
start=timeGetTime_()
For n=1 To 100000000
x=Max2(a,b)
y=Min2(a,b)
Next
stop=timeGetTime_()
text$+"Max2()/Min2(): "+Str(stop-start)+"ms"+#LF$
n.l=0
start=timeGetTime_()
For n=1 To 100000000
x=Max3(a,b)
y=Min3(a,b)
Next
stop=timeGetTime_()
text$+"Max3()/Min3(): "+Str(stop-start)+"ms"+#LF$
n.l=0
start=timeGetTime_()
For n=1 To 100000000
x=Max4(a,b)
y=Min4(a,b)
Next
stop=timeGetTime_()
text$+"Max4()/Min4(): "+Str(stop-start)+"ms"+#LF$
;This is a example of "proper" coding, the Max and Min is done using If's in the loop/code.
n.l=0
start=timeGetTime_()
For n=1 To 100000000
If a>b : x=a : Else : x=b : EndIf ;Does the same as i.e x=Max2(a,b)
If a<b : y=a : Else : y=b : EndIf ;Does the same as i.e y=Min2(a,b)
Next
stop=timeGetTime_()
text$+"If long: "+Str(stop-start)+"ms"+#LF$
n.l=0
start=timeGetTime_()
For n=1 To 100000000
If c>d : z1=c : Else : z1=d : EndIf ;Does the same as i.e x=Max4(a,b)
If c<d : z2=c : Else : z2=d : EndIf ;Does the same as i.e y=Min4(a,b)
Next
stop=timeGetTime_()
text$+"If single: "+Str(stop-start)+"ms"+#LF$
n.l=0
start=timeGetTime_()
For n=1 To 100000000
If cc>dd : zz1=cc : Else : zz1=dd : EndIf
If cc<dd : zz2=cc : Else : zz2=dd : EndIf
Next
stop=timeGetTime_()
text$+"If double: "+Str(stop-start)+"ms"+#LF$
n.l=0
start=timeGetTime_()
For n=1 To 100000000
x=Max5(a,b)
x=Min5(a,b)
Next
stop=timeGetTime_()
text$+"Max5()/Min5() long: "+Str(stop-start)+"ms"+#LF$
n.l=0
start=timeGetTime_()
For n=1 To 100000000
z1=Max5(c,d)
z2=Min5(c,d)
Next
stop=timeGetTime_()
text$+"Max5()/Min5() single: "+Str(stop-start)+"ms"+#LF$
n.l=0
start=timeGetTime_()
For n=1 To 100000000
zz1=Max5(cc,dd)
zz2=Min5(cc,dd)
Next
stop=timeGetTime_()
text$+"Max5()/Min5() double: "+Str(stop-start)+"ms"+#LF$
MessageRequester("Results",text$)
timeEndPeriod_(1)