Quicker choose function...

Share your advanced PureBasic knowledge/code with the community.
User avatar
Michael Vogel
Addict
Addict
Posts: 2807
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Quicker choose function...

Post by Michael Vogel »

I often need a function which returns a specific value if a condition is true and another value if not.
For example, I draw a box in a different color if the mouse will be moved over the box, this will be handled with something like DrawBox(index, Choose(Bool(index=mouse), ColorHighlight, ColorDefault)).

But the Choose function is very slow...

Code: Select all

Procedure Choose(a,b,c)
	If a
		ProcedureReturn b
	Else
		ProcedureReturn c
	EndIf
EndProcedure
So I use now this one which is nearly 100 times quicker...

Code: Select all

Macro ist(a,b,c)
	(Bool(a)*(b)+Bool(a)!1*(c))
EndMacro
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Here's the speed test...

Code: Select all

CompilerSet Debugger=0, Assembler=1

Procedure Choose1(a,b,c)
	If a
		ProcedureReturn b
	Else
		ProcedureReturn c
	EndIf
EndProcedure
Macro Choose2(a,b,c)
	(Bool(a)*b+Bool(a)!1*c)
EndMacro

#Loop=9999999
#Add1=123
#Add2=1000000000-#Add1*#Loop
t1-ElapsedMilliseconds()
For i=0 To #Loop
	z1+Choose1(Bool(i<>5),#Add1,#Add2)
Next i
t1+ElapsedMilliseconds()

t2-ElapsedMilliseconds()
For i=0 To #Loop
	z2+Choose2(Bool(i<>5),#Add1,#Add2)
Next i
t2+ElapsedMilliseconds()

MessageRequester("Test using "+Str(#Add1)+" / "+Str(#Add2),Str(z1)+", "+Str(t1)+" ms"+#CR$+Str(z2)+", "+Str(t2)+" ms")
#NULL
Addict
Addict
Posts: 1499
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Quicker choose function...

Post by #NULL »

i think you should put braces around the parameters in the macro body to make shure that operator precedence works as expected, see this one:

Code: Select all

Macro Choose2(a,b,c)
   (a*b+(a!1)*c)
EndMacro

Debug Choose2(1-1, -123, 456)

Macro Choose3(a,b,c)
   ((a)*(b)+((a)!1)*(c))
EndMacro

Debug Choose3(1-1, -123, 456)
second version will still give the wrong result for a = 1-2.

it's only a poblem if you don't use Bool() directly at the call, but you might want to move it into the body anyway.
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: Quicker choose function...

Post by Lunasole »

No sense to optimize such. I see from your test It brings only 3% difference for 9999999 calls on Pentium 4 level CPU (while absolute time is around 100ms), and by other test I launched, variant which uses procedure is ~35% faster:

Code: Select all

EnableExplicit
DisableDebugger
; 1. Initial params and common code
OpenConsole("[Testing Facility v1.0.0.1] :3")
Define Time1, Time2, Counter, Count = 9999999
Macro TestCode (Time, Code)
	Time = ElapsedMilliseconds()
	For Counter = 1 To Count
		Code
	Next Counter
	Time = ElapsedMilliseconds() - Time
EndMacro

; 2. User code
; --------------------------------------------------- \
; declare someting
Procedure Choose1(a,b,c)
   If a
      ProcedureReturn b
   Else
      ProcedureReturn c
   EndIf
EndProcedure
Macro Choose2(a,b,c)
   (Bool(a)*b+Bool(a)!1*c)
EndMacro

Define z1.q
Define z2.q

Macro Code1 ; code executed inside cycle 1
	z1+Choose1(Random(1),Random(1),Random(1))
EndMacro

Macro Code2 ; code executed inside cycle 2
	; do something-2
	z2+Choose2(Random(1),Random(1),Random(1))
EndMacro
; --------------------------------------------------- /

; 3. Execute tests
TestCode(Time1, Code1)
TestCode(Time2, Code2)
; 4. Display results
PrintN("Cycle 1: " + Str(Time1) + "ms")
PrintN("Cycle 2: " + Str(Time2) + "ms")
PrintN("------------")
If Time2 > Time1
	PrintN("First is faster: " + StrF(100.0 - (Time1 / (Time2 / 100.0)), 2) + "%")
ElseIf Time1 > Time2
	PrintN("Second is faster: " +StrF(100.0 - (Time2 / (Time1 / 100.0)), 2) + "%")
Else
	PrintN("Equal results")
EndIf
Input()
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
Post Reply