Page 2 of 3
Re: IIF functionality made simple
Posted: Mon Nov 09, 2009 9:08 pm
by Kaeru Gaman
mesozorn wrote:Zero is actually a real result, because it means the process took less than a single millisecond.
no it doesn't.
zero means, that the process took less than one timeslice, that means less than 13ms.
so, comparing two processes and getting results of zero, can mean one needs 2 and the other needs 6 ms, wich would mean the second needs threefold the time of the first.
thus I said, zero is no result, because it tells you nothing.
screw it higher to 1000 - 60000 ms, to get something that is worth being called a result.
and again - run it without debugger, you would need a MsgBox to show the results then.
Re: IIF functionality made simple
Posted: Mon Nov 09, 2009 9:18 pm
by mesozorn
Kaeru Gaman wrote:no it doesn't.
zero means, that the process took less than one timeslice, that means less than 13ms.
What is your backup for this statement? In the documentation for ElapsedMilliseconds(), it says nothing about 13ms "timeslices". And if it does work this way, why is it not mentioned in the documentation?
In any case, for me the following:
Code: Select all
e=ElapsedMilliseconds()
For x=1 To 100000000
z=Val(Str(5.5>5.6))
Next x
MessageRequester("Test result",Str(ElapsedMilliseconds()-e))
... without the debugger produces a result of 3250 milliseconds after one hundred million repetitions. Which gives a result of 0.0000325 milliseconds per cycle, and which means that my original test of ten thousand cycles would still only take 0.325 milliseconds, which is still less than one single millisecond as originally asserted. Thus the Val(Str()) usage can hardly be said to consume much resource.
Re: IIF functionality made simple
Posted: Mon Nov 09, 2009 9:31 pm
by Kaeru Gaman
> why is it not mentioned in the documentation?
because it's an OS specific problem, not PB specific.
ElapsedMilliseconds is a wrapper of the API-Function to return the milliseconds.
you can adjust the precision to a single millisecond by some API calls, there is code in the forums.
> What is your backup for this statement?
knowledge, experience, dozens of discussions in the forums about that issue..
but ok, also something definitely and printed:
http://www.geisswerks.com/ryan/FAQS/timing.html
have fun
Re: IIF functionality made simple
Posted: Mon Nov 09, 2009 9:46 pm
by mesozorn
Kaeru Gaman wrote:you can adjust the precision to a single millisecond by some API calls, there is code in the forums.
I am definitely going to need to do this for all future programs then, as I can't stand imprecision on any scale. In any case, if you check the second part of my post above (which may have been missed because I edited it in after further testing) you can see that in this specific case, even higher volume testing reveals Val(Str()) not to be a significant issue in terms of time consumption, even when larger cycles are used.
Re: IIF functionality made simple
Posted: Mon Nov 09, 2009 10:56 pm
by SFSxOI
mesozorn wrote:Kaeru Gaman wrote:no it doesn't.
zero means, that the process took less than one timeslice, that means less than 13ms.
What is your backup for this statement? In the documentation for ElapsedMilliseconds(), it says nothing about 13ms "timeslices". And if it does work this way, why is it not mentioned in the documentation?
In any case, for me the following:
Code: Select all
e=ElapsedMilliseconds()
For x=1 To 100000000
z=Val(Str(5.5>5.6))
Next x
MessageRequester("Test result",Str(ElapsedMilliseconds()-e))
... without the debugger produces a result of 3250 milliseconds after one hundred million repetitions. Which gives a result of 0.0000325 milliseconds per cycle, and which means that my original test of ten thousand cycles would still only take 0.325 milliseconds, which is still less than one single millisecond as originally asserted. Thus the Val(Str()) usage can hardly be said to consume much resource.
That code gives me 10265
this code gives me 8331
Code: Select all
e=ElapsedMilliseconds()
For x=1 To 100000000
z=5.5>5.6
Next x
MessageRequester("Test result",Str(ElapsedMilliseconds()-e))
which is correct (or as near almost correct for the discussion)?
Re: IIF functionality made simple
Posted: Mon Nov 09, 2009 11:10 pm
by idle
I'm not saying your solution is bad but it's not suitable to use in all instances if it's used in GUI window loop in response to a button click then yes go for your life but if it's used in a loop controlling the flow then no it's almost 10x slower
Code: Select all
Global tt.TIMECAPS
timeGetDevCaps_(@tt, SizeOf(TIMECAPS))
timeBeginPeriod_(tt\wPeriodMin)
Procedure.s IIFEval(expr,y$,n$)
If expr=1:ProcedureReturn y$
Else:ProcedureReturn n$
EndIf
EndProcedure
Procedure IIFEvaln(expr,y,n)
If expr=1
ProcedureReturn y
Else
ProcedureReturn n
EndIf
EndProcedure
Macro IIFn(expr,y,n)
IIFEvaln(Val(Str(1 And expr)),y,n)
EndMacro
Macro IIF(expr,y,n)
IIFEval(Val(Str(1 And expr)),y,n)
EndMacro
Debug IIF(5.5>5.4,"yes","no")
Debug IIF(5.5>5.6,"yes","no")
Debug IIF(5.5=5.5,"yes","no")
Debug IIFn(5.5>5.7,200,100)
Debug iifn(5.5>5.4 And 5>3,200,100)
lp = 10000000
st = GetTickCount_()
For a = 1 To lp
x= IIFn(5>7,200,100)
Next
et1.f = (GetTickCount_() - st) / lp
st = GetTickCount_()
For a = 1 To lp
If 5 > 7
x = 200
Else
x = 100
EndIf
Next
et2.f = (GetTickCount_() - st) / lp
MessageRequester("test", "iif " + StrF(et1,6) + " if " + StrF(et2,6))
Re: IIF functionality made simple
Posted: Mon Nov 09, 2009 11:16 pm
by mesozorn
SFSxOI wrote:That code gives me 10265
Turn off the debugger and you'll get a result closer to three seconds. I got around ten as well while the debugger was turned on.
You need to use the Val(Str()) version if you want to evaluate float/decimal number expressions within these custom IIF() macros. I leave it in so that the function is all-purpose and can handle every variation of expression/action.
Re: IIF functionality made simple
Posted: Mon Nov 09, 2009 11:22 pm
by mesozorn
idle wrote:I'm not saying your solution is bad but it's not suitable to use in all instances if it's used in GUI window loop in response to a button click then yes go for your life but if it's used in a loop controlling the flow then no it's almost 10x slower
It's simply currently the only one-shot version of an IIF statement that can be used within PB for all evaluation scenarios. Good or bad as it may be, it's all there is that works. If you know for a fact you won't need to evaluate floats, you can change it to a simple one-call procedure that doesn't need the Val(Str()) component. You can have another version that does use it specifically for when you want to use floats, or when you're not sure what the expression will contain. Or you can do a different sort of evaluation that doesn't involve an IIF statement.
But if you want an IIF that can be plugged in as a parameter to another procedure or statement, and can also handle float expressions, this is what's currently available until that new Boolean() function is introduced in 4.5 or whenever.
Re: IIF functionality made simple
Posted: Mon Nov 09, 2009 11:31 pm
by Kaeru Gaman
but it is fishy, even more fishy than the Or 0 workaround.
one more thing for duration tests: do not test only a single condition.
in this case, you would need to test all three comparators with all two results, True and False, so you would need six tests within the testloop.
and, since you normally would test variables and not literals, use variables in the test.
... but it's meaningless anyways, it's fish too fishy to talk about reason.
wait for the Boolean() directive, coming in 4.5 or 4.6 ...
Re: IIF functionality made simple
Posted: Mon Nov 09, 2009 11:35 pm
by idle
you get 5/5 for style and I liked your solution, its just a pity it can't be done faster!
Re: IIF functionality made simple
Posted: Mon Nov 09, 2009 11:48 pm
by mesozorn
Yes, faster would be better, and Boolean() will no doubt provide that. I invented my version a while back because I needed it then and could not wait for future development. This was many months ago and boolean() wasn't even promised or anticipated at the time, so I had to make do with this hack. I only use it when it's needed as a parameter, never as a stand-alone conditional evaluation.
Re: IIF functionality made simple
Posted: Tue Nov 10, 2009 12:55 am
by mesozorn
I've dramatically improved the speed performance of the IIF macro, and managed to do away with the need for Val(Str()) in the process while preserving the float evaluation integrity. I've pasted the change directly into Idle's time test example below to demonstrate. It's not perfect yet but it's much, much faster than before.
Code: Select all
Global tt.TIMECAPS
timeGetDevCaps_(@tt, SizeOf(TIMECAPS))
timeBeginPeriod_(tt\wPeriodMin)
Procedure.s IIFEval(expr,y$,n$)
If expr=1:ProcedureReturn y$
Else:ProcedureReturn n$
EndIf
EndProcedure
Procedure IIFEvaln(expr,y,n)
If expr=1
ProcedureReturn y
Else
ProcedureReturn n
EndIf
EndProcedure
Macro IIFn(expr,y,n)
IIFEvaln(1-(1 And Not(expr)),y,n)
EndMacro
Macro IIF(expr,y,n)
IIFEval(1-(1 And Not(expr)),y,n)
EndMacro
Debug IIF(5.5>5.4,"yes","no")
Debug IIF(5.5>5.6,"yes","no")
Debug IIF(5.5=5.5,"yes","no")
Debug IIFn(5.5>5.7,200,100)
Debug iifn(5.5>5.4 And 5>3,200,100)
lp = 10000000
st = GetTickCount_()
For a = 1 To lp
x= IIFn(5>7,200,100)
Next
et1.f = (GetTickCount_() - st) / lp
st = GetTickCount_()
For a = 1 To lp
If 5 > 7
x = 200
Else
x = 100
EndIf
Next
et2.f = (GetTickCount_() - st) / lp
MessageRequester("test", "iif " + StrF(et1,6) + " if " + StrF(et2,6))
Also my original crude time test:
Code: Select all
e=ElapsedMilliseconds()
For x=1 To 100000000
z=1-(1 And Not(5.5>5.3))
Next x
MessageRequester("Test result",Str(ElapsedMilliseconds()-e))
...now for me returns just under 300 milliseconds for one hundred million cycles, as opposed to 3250 milliseconds before. About a 10x improvement in this (admittedly crude and incomplete) test example.
Re: IIF functionality made simple
Posted: Tue Nov 10, 2009 1:25 am
by idle
That's heaps better, I think the additional time in the numeric version is mostly due to the procedure call, so nothing much else you could do.
Not sure about the string version though, still looking
see what comes from all the bitching and bickering.
well done it's a good improvement.
couldn't you just use this though?
Code: Select all
Macro IIFn(expr,y,n)
IIFEvaln((Not(expr)),n,y)
EndMacro
Macro IIF(expr,y,n)
IIFEval((Not(expr)),n,y)
EndMacro
or this and is probably quicker than a not
Code: Select all
Macro IIFn(expr,y,n)
IIFEvaln((1 And(expr)),y,n)
EndMacro
Macro IIF(expr,y,n)
IIFEval((1 And(expr)),y,n)
EndMacro
Re: IIF functionality made simple
Posted: Tue Nov 10, 2009 1:55 am
by Kaeru Gaman
why 1- and Not, when you have the And..?
and as I already said, use all variations and variables...
Code: Select all
e=ElapsedMilliseconds()
a.f = 5.5
b.f = 5.3
c.f = 5.3
For x=1 To 100000000
z=(1 And ( a > b ))
z=(1 And ( b > a ))
z=(1 And ( a < b ))
z=(1 And ( b < a ))
z=(1 And ( a = b ))
z=(1 And ( c = b ))
Next x
MessageRequester("Test result",Str(ElapsedMilliseconds()-e))
Re: IIF functionality made simple
Posted: Tue Nov 10, 2009 2:30 am
by mesozorn
idle wrote:see what comes from all the bitching and bickering.
well done it's a good improvement.
Thanks, evolution comes mostly from struggle right?
idle wrote:couldn't you just use this though?
Code: Select all
Macro IIFn(expr,y,n)
IIFEvaln((Not(expr)),n,y)
EndMacro
Macro IIF(expr,y,n)
IIFEval((Not(expr)),n,y)
EndMacro
Yep that seems to work too and is cleaner-looking, nice one. The reason I didn't think that would work is because for some reason on its own, this:
Code: Select all
z=(1-(1 And Not(5.5>5.6)))
Debug z
z=(1-(1 And Not(5.5>5.3)))
Debug z
...works correctly, whereas (for me) using "NOT" by itself:
Code: Select all
z=(Not(5.5>5.6))
Debug z
z=(Not(5.5>5.3))
Debug z
...does not work, oddly. So I don't know why it works in the macro but not by itself, but that's why it didn't seem likely to work. I'm probably just missing something from being too tired...