Boolean / Logical Expression Shortcuts

Started by kevin, August 28, 2009, 10:08:03 PM

Previous topic - Next topic

kevin

  Boolean / Logical Expression Shortcuts

   The follow code snippets demo various approaches for achieving the same calculations/results using various boolean/logical expressions.    Why would you want to ?  Well, sometimes you can stumble upon alternative methods that might actually execute faster than the built in functionality.  Which can be very useful if you're trying to squeeze out a bit more performance, or perhaps you're trying to write really unreadable code... :)

   However, It's well worth keep in mind that just because Method A might be faster than method B today,  it may not be in the future.  So it always pays to query the performance of any approach you're using.


Related To
A Crash Course In Optimization



kevin

#1
 Swapping Values

 This was original written as query to the performance in DB eons ago.  Interestingly,  it's actually quicker than SWAP providing the operations are inline.


PlayBASIC Code: [Select]
   type tTiming
Name$
StartTime
TotalTime
AverageTime#
Frames
endtype

Dim Times(100) as tTiming

// These flags are used for the display routines
Global ThisTest
Global DisplayLargest=true


// number of cycles to execute each test. We need a lot of tests in order to see any bias in the performance
MaxTests=5000


TestCounter=1000

// Values we're swapping
A =130
B =150

Do
Cls 0


print "Tests = "+str$(TestCounter)
print " A = "+str$(A);
print " B = "+str$(B);

ThisTest=0

StartTiming(ThisTest,"Swap Operation")
for lp=0 to MaxTests
swap A,B
next
DisplayResult(ThisTest)


StartTiming(ThisTest,"3 Move Swap")
for lp=0 to MaxTests
t=a
a=b
b=t
next
DisplayResult(ThisTest)


StartTiming(ThisTest,"4 Move Swap")
for lp=0 to MaxTests
t1=a
t2=b
a=t2
b=t1
next
DisplayResult(ThisTest)



StartTiming(ThisTest,"Xor Swap")
for lp=0 to MaxTests
maskab= (a xor b)
B=-1-((-1 xor a) xor maskab)
A=-1-((-1 xor b) XOR maskab)
next
DisplayResult(ThisTest)


StartTiming(ThisTest,"Mult/Div Swap")
for lp=0 to MaxTests
s=a*b
a=s/a
b=s/b
next
DisplayResult(ThisTest)



StartTiming(ThisTest,"Delta Swap")
for lp=0 to MaxTests
delta=(a-b)
a=a-delta
b=b+delta
next
DisplayResult(ThisTest)


Sync
decloop TestCounter


Print "Test Complete"
DisplayLargest=False
DisplayOrdersResults(ThisTest)

Sync
waitkey



Function DisplayResult(ThisTest)
s$=make$(" ",30)
message$= right$(s$+upper$(Times(ThisTest).Name$),30)

Message$=Message$+" Time:"+str$( EndTiming(ThisTest))
print Message$
inc ThisTest
EndFunction



Function StartTiming(Index,Message$)
Times(Index).Name$=Message$
Times(Index).StartTime=Timer()
Times(Index).Frames=Times(Index).Frames+1
EndFunction

Function EndTiming(Index)
Dt=Timer()-Times(Index).StartTime
Times(Index).TotalTime=Times(Index).TotalTime+Dt
Average#=float(Times(Index).TotalTime)/Times(Index).Frames
Times(Index).AverageTime=Average#
EndFunction Average#




Function DisplayOrdersResults(NumberOfItems)
Dim Mask(NumberOFItems)

Ink $ff00ff
print "RESULTS - Fastest to Slowest"
Ink $ff0000

for lp=0 to NumberOfItems-1
Lowest# =99999
LowestIndex =0
for SearchLp=0 to NumberOfItems-1
if Mask(Searchlp)=0
if Lowest#>Times(SearchLP).AverageTime
Lowest#=Times(SearchLP).AverageTime
LowestIndex=Searchlp
endif
endif
Login required to view complete source code




kevin

#2
Highest Value

 This is just some experiments with a few of detecting the highest of the two integer values.



PlayBASIC Code: [Select]
   type tTiming
Name$
StartTime
TotalTime
AverageTime#
Frames
endtype

Dim Times(100) as tTiming
// These flags are used for the display routines
Global ThisTest
Global DisplayLargest=true


// number of cycles to execute each test. We need a lot of tests in order to see any bias in the performance
MaxTests=5000



TestCounter=1000


// Values we're comparing
A =130
B =150


Do
Cls 0


print "Tests = "+str$(TestCounter)
print " A = "+str$(A);
print " B = "+str$(B);

ThisTest=0

StartTiming(ThisTest,"IF / THEN")
for lp=0 to MaxTests
// use IF/THEN
C=A
if B>A then C=B
next
DisplayResult(ThisTest,C)


StartTiming(ThisTest,"IF / Else /ENDIF")
for lp=0 to MaxTests
// use IF/THEN
if B>A
B=B
else
C=A
endif
next
DisplayResult(ThisTest,C)


StartTiming(ThisTest,"MaxVal Function")
for lp=0 to MaxTests
c=maxval(a,b)
next
DisplayResult(ThisTest,C)




StartTiming(ThisTest,"Boolean With Mult")
for lp=0 to MaxTests
// Find the largest of two values
C= ((A>=B) * A) + ((A<B) * B)
next
DisplayResult(ThisTest,C)

StartTiming(ThisTest,"Boolean with bitwise and")
for lp=0 to MaxTests
// Find the largest of two values (without multiples)
C= ((-1+(A<=B)) & A) + ((-1+(A>B)) & B)
next
DisplayResult(ThisTest,C)


StartTiming(ThisTest,"Delta Method 1")
for lp=0 to MaxTests
// Delta method, find diff between values, then Add differnece if B larger then A.
C= A+((B-A)*(B>A))
next
DisplayResult(ThisTest,C)


StartTiming(ThisTest,"Delta Method 2")
for lp=0 to MaxTests
// No mult version of Delta method
C= A+(-1+(A>B) &(B-A))
next
DisplayResult(ThisTest,C)

Sync
decloop TestCounter


Print "Test Complete"
DisplayLargest=False
DisplayOrdersResults(ThisTest)

Sync
waitkey



Function DisplayResult(ThisTest,C)
s$=make$(" ",30)
message$= right$(s$+upper$(Times(ThisTest).Name$),30)

if DisplayLargest
Message$=Message$+" Largest Value:"+str$( c)
endif
Message$=Message$+" Time:"+str$( EndTiming(ThisTest))
print Message$
inc ThisTest
EndFunction



Function StartTiming(Index,Message$)
Times(Index).Name$=Message$
Times(Index).StartTime=Timer()
Times(Index).Frames=Times(Index).Frames+1
EndFunction

Function EndTiming(Index)
Dt=Timer()-Times(Index).StartTime
Times(Index).TotalTime=Times(Index).TotalTime+Dt
Average#=float(Times(Index).TotalTime)/Times(Index).Frames
Times(Index).AverageTime=Average#
EndFunction Average#




Function DisplayOrdersResults(NumberOfItems)
Dim Mask(NumberOFItems)

Ink $ff00ff
print "RESULTS - Fastest to Slowest"
Ink $ff0000

for lp=0 to NumberOfItems-1
Login required to view complete source code



kevin

#3
  Value Within Range

 In this test, we're looking at some ways of detecting if a value falls within an inclusive (can be equal to the bottom and lower limits) range.  

 Note: we're assuming the range limited are in order here.  


PlayBASIC Code: [Select]
   type tTiming
Name$
StartTime
TotalTime
AverageTime#
Frames
endtype

Dim Times(100) as tTiming

// These flags are used for the display routines
Global ThisTest
Global DisplayLargest=true


// number of cycles to execute each test. We need a lot of tests in order to see any bias in the performance
MaxTests=5000

TestCounter=1000

// Ranges we're comparing within
RangeBottom=100
RangeTop=200

Value=150

Do
Cls 0


print "Tests = "+str$(TestCounter)
print " Range Bot = "+str$(RangeBottom);
print " Range Top = "+str$(RangeTop);
print " Test Value = "+str$(Value)

ThisTest=0

StartTiming(ThisTest,"Range Function")
for lp=0 to MaxTests
result=range(Value,RangeBottom,RangeTop)
next
DisplayResult(ThisTest)
print Result



StartTiming(ThisTest,"Combined Compare")
for lp=0 to MaxTests

// Combined Compare
Result=0
if (Value>=RangeBottom) and (Value<=RangeTop)
result=true
endif
next
DisplayResult(ThisTest)
print Result



StartTiming(ThisTest,"Split Compare")
for lp=0 to MaxTests

// Combined Compare
Result=0
if Value>=RangeBottom
if Value<=RangeTop
result=true
endif
endif

next
DisplayResult(ThisTest)
print Result



// Boolean Compare
StartTiming(ThisTest,"Boolean Compare (AND)")
for lp=0 to MaxTests
// Combined Compare
Result= (Value>=RangeBottom) and (Value<=RangeTop)
next
DisplayResult(ThisTest)
print Result

// Boolean Compare
StartTiming(ThisTest,"Boolean Compare (SUBTRACT)")
for lp=0 to MaxTests
// Combined Compare
Result= (Value>=RangeBottom) - (Value>RangeTop)
next
DisplayResult(ThisTest)
print Result


// Boolean Compare
StartTiming(ThisTest,"Split Boolean Compare")
for lp=0 to MaxTests
// Combined Compare
Result= (Value>=RangeBottom)
if Value>RangeTop
result=false
endif

next
DisplayResult(ThisTest)
print Result



Sync
decloop TestCounter


Print "Test Complete"
DisplayLargest=False
DisplayOrdersResults(ThisTest)

Sync
waitkey



Function DisplayResult(ThisTest)
s$=make$(" ",30)
message$= right$(s$+upper$(Times(ThisTest).Name$),30)

Message$=Message$+" Time:"+str$( EndTiming(ThisTest))
print Message$
inc ThisTest
EndFunction



Function StartTiming(Index,Message$)
Times(Index).Name$=Message$
Times(Index).StartTime=Timer()
Times(Index).Frames=Times(Index).Frames+1
EndFunction

Function EndTiming(Index)
Dt=Timer()-Times(Index).StartTime
Times(Index).TotalTime=Times(Index).TotalTime+Dt
Average#=float(Times(Index).TotalTime)/Times(Index).Frames
Times(Index).AverageTime=Average#
EndFunction Average#


Login required to view complete source code



kevin

#4
 Distance/Range Checking

  The follow examples run through various methods for detecting if an Target object is within a range of the Source object.    You commonly find this type of calc in collisions.   Interestingly the inline version is quickest in PB1.64j.    Although you'd probably get the better results in a real world situation by screening the X or Y axis first, before falling into the distance calc.   If objects are spread out, then this will act as early reject, otherwise we're calcing the distance every update.  



PlayBASIC Code: [Select]
   type tTiming
Name$
StartTime
TotalTime
AverageTime#
Frames
endtype

Dim Times(100) as tTiming

// These flags are used for the display routines
Global ThisTest
Global DisplayLargest=true


// number of cycles to execute each test. We need a lot of tests in order to see any bias in the performance
MaxTests=5000

TestCounter=500

// Ranges we're comparing within

ThisRange=400
RangeSquared=ThisRange*ThisRange

SrcObjectX=100
SrcObjectY=100
TargetX=200
TargetY=200



Do
Cls 0

print "Tests = "+str$(TestCounter)

ThisTest=0

StartTiming(ThisTest,"GetDistance Function")
for lp=0 to MaxTests
result=GetDistance2D(TargetX,TargetY,SrcObjectX,SrcObjectY)< ThisRange
next
DisplayResult(ThisTest)
print result




StartTiming(ThisTest,"Check Distance (SQRT) #1")
for lp=0 to MaxTests
result=CheckDistance(TargetX,TargetY,SrcObjectX,SrcObjectY,ThisRange)
next
DisplayResult(ThisTest)
print result


StartTiming(ThisTest,"Check Distance (SQRT) #2")
for lp=0 to MaxTests
result=CheckDistance2(TargetX,TargetY,SrcObjectX,SrcObjectY,ThisRange)
next
DisplayResult(ThisTest)
print result


StartTiming(ThisTest,"Check Distance (SQUARED) #3")
for lp=0 to MaxTests
result=CheckDistance3(TargetX,TargetY,SrcObjectX,SrcObjectY,ThisRange)
next
DisplayResult(ThisTest)
print result


StartTiming(ThisTest,"Check Distance (Pre SQUARED) #4")
for lp=0 to MaxTests
result=CheckDistance4(TargetX,TargetY,SrcObjectX,SrcObjectY,RangeSquared)
next
DisplayResult(ThisTest)
print result


StartTiming(ThisTest,"Inline (squared distance)")
for lp=0 to MaxTests

DiffX = SrcObjectX-TargetX
DiffY = SrcObjectY-TargetY
result=(DiffX*DiffX + DiffY*DiffY) < RangeSquared

next
DisplayResult(ThisTest)
print result



StartTiming(ThisTest,"Inline (squared distance & X axis compare)")
for lp=0 to MaxTests

if SrcObjectX<TargetX
DiffX=TargetX-SrcObjectX
else
DiffX=SrcObjectX-TargetX
endif
if DiffX<ThisRange
DiffY = SrcObjectY-TargetY
result=(DiffX*DiffX + DiffY*DiffY) < RangeSquared
else
result=0
endif

next
DisplayResult(ThisTest)
print result


StartTiming(ThisTest,"Inline (squared distance & X/Y axis compare)")
for lp=0 to MaxTests

result=0
if SrcObjectX<TargetX
DiffX=TargetX-SrcObjectX
else
DiffX=SrcObjectX-TargetX
endif
if DiffX<ThisRange
if SrcObjectY<TargetY
DiffY=TargetY-SrcObjectY
else
DiffY=SrcObjectY-TargetY
endif

if DiffY<ThisRange
result=(DiffX*DiffX + DiffY*DiffY) < RangeSquared
endif
endif

next
DisplayResult(ThisTest)
print result



Sync
decloop TestCounter


Print "Test Complete"
DisplayLargest=False
DisplayOrdersResults(ThisTest)
Login required to view complete source code