Page 1 of 1
For/Next with [float] variable Step
Posted: Tue Sep 17, 2013 2:16 pm
by PB
I always wanted a For/Next with a [float] variable for Step,
and it was mandatory for me that it still looked Basic-like.
This is what I came up with quickly. Seems to work okay,
but I may have missed something. Use at your own risk!
It uses two macros to do the magic. The macro "Forr" sets
up the loop, and takes 4 parameters: variable name, start,
finish, and step. If start>finish then the loop counts up, but
if start<finish then the loop counts down (like "Step -1").
The step parameter can be a variable, or float, or BOTH!
The second macro, "Nextt()", just finishes the loop. Enjoy!
Code: Select all
; For/Next with floats and/or variable for Step.
; By PB -- Do whatever the heck you want with it.
; Yes, I know other float values affect precision!
Macro Forr(var,start,finish,inc)
CompilerIf start<finish
var=start-inc : While var<finish : var+inc
CompilerElse
var=start+inc : While var>finish : var-inc
CompilerEndIf
EndMacro
Macro Nextt()
Wend
EndMacro
stp.f=0.5 ; Float *and* variable for Step!
Forr(a.f,1,5,stp) ; For a = 1 To 5 Step 0.5
Debug a ; 1.0, 1.5, 2.0, 2.5, 3.0, [...]
Nextt()
Forr(a.f,4.5,1,0.5) ; For a = 4.5 To 1 Step -0.5
Debug a ; 4.5, 4.0, 3.5, 3.0, 2.5, [...]
Nextt()
Re: For/Next with [float] variable Step
Posted: Tue Sep 17, 2013 4:00 pm
by Thorium
Here is the fix for the incorrect iterations because of inprecisision of floats.
It fixes it by casting the float point to a fixed point and doing a round.
The precision is 3 digits after point. Increase multiply to add higher precision, but remember you trade it off for how high the number can go, it's fixed point comparision. And it's slow as hell.
It still does not fix the infinit loops on small fractions. Thats also possible to fix but makes it even slower.
Code: Select all
Macro Forr(var,start,finish,inc)
CompilerIf start<finish
var=start-inc
While Round(var * 1000, #PB_Round_Nearest) < Round(finish * 1000, #PB_Round_Nearest)
var+inc
CompilerElse
var=start+inc
While Round(var * 1000, #PB_Round_Nearest) > Round(finish * 1000, #PB_Round_Nearest)
var-inc
CompilerEndIf
EndMacro
Macro Nextt()
Wend
EndMacro
Forr(a.f, 1, 1.1, 0.05)
Debug a
Nextt()
Re: For/Next with [float] variable Step
Posted: Tue Sep 17, 2013 4:07 pm
by Demivec
You can't use 'CompilerIF/CompilerElse/CompilerEndif' in the macros the way you have because they won't be able to check the value of a runtime variable at compiletime.
Also, after the macro's code appears the compiler functions will have become fixed and not changeable. This means that only one of the conditions will be compiled for every call of the macro no matter what parameters are used as part of the call. All the loops will count up or they all will count down.
@Edit: It appears that the compiler functions are evaluated for each use of the macro and I was wrong on this point. I think this is different for previous versions of PureBasic. I'm glad it appears to have been changed.
Re: For/Next with [float] variable Step
Posted: Tue Sep 17, 2013 4:55 pm
by BorisTheOld
It's a bad policy to use floating point variables for loop counters and loop increments. This has been discussed at length in other threads.
Loop counts are, by definition, integral values. So even if floating point values are needed in the loop, the actual counting should always be done using integer values. This will prevent rounding errors from causing incorrect loop counts. So instead of trying to use:
Code: Select all
For A.d = 1 To 1.1 Step 0.05
.
.
Next
Use the following instead and, if needed, scale the value of the loop counter back to a floating point value.
Code: Select all
For X.i = 100 To 110 Step 5
.
. A = X / 100
.
Next
Re: For/Next with [float] variable Step
Posted: Tue Sep 17, 2013 4:57 pm
by Thorium
It works as long as you dont use variables for start and finish.
Re: For/Next with [float] variable Step
Posted: Tue Sep 17, 2013 5:03 pm
by jassing
He's not using (the equivilant) of
for x = a to b step c
(which, doesn't work anyway)
The usage is only good for the
for x = 1 to 10 step 2
type of for loop.
Re: For/Next with [float] variable Step
Posted: Tue Sep 17, 2013 5:10 pm
by BorisTheOld
One first creates integer variables for the From, To, and Step values. Then one scales the floating point values (multiplying by 10^n) to create suitable integer values.
But the problem still exists that arbitrary rounding decisions still need to be made when scaling the floating point numbers to integer values. And this can affect the actual number of loop cycles, which may or may not be a problem.
Re: For/Next with [float] variable Step
Posted: Tue Sep 17, 2013 7:02 pm
by minimy
Hi PB and all the people of the post.
The first is thank for share. The idea is very interesting.
I think this is the easy way to do this, and no have problems with division by cero.
Code: Select all
;
NumStart= 0
NumEnd = 5
Stip.f = 0.5
NumFinis= NumEnd/Stip
For X.i = NumStart To NumFinis
Debug X * Stip
Next
Re: For/Next with [float] variable Step
Posted: Wed Sep 18, 2013 1:34 am
by Demivec
Thorium wrote:It works as long as you dont use variables for start and finish.
@Thorium, jassing: You are correct. I think it would be an easy mistake to make though because nothing indicates otherwise.
It also appears that I was wrong about the compiler functions only being evaluated once for all uses of the macro. I recall that was the way it functioned in the past. It appears that it has been changed and the compiler functions at each place the macro code is used. That may open up some possibilities for creating more procedure-like macros that vary depending on the values of compiler-evaluated functions.
Re: For/Next with [float] variable Step
Posted: Sun Sep 22, 2013 1:21 pm
by mk-soft
Maybe so
Code: Select all
Macro ForF(varf,startf,endf,stepf)
If startf < endf
varf = startf - stepf
Else
varf = startf + stepf
EndIf
While (startf < endf And Round(varf * 1000, #PB_Round_Nearest) < Round(endf * 1000, #PB_Round_Nearest)) Or (startf > endf And Round(varf * 1000, #PB_Round_Nearest) > Round(endf * 1000, #PB_Round_Nearest))
If startf < endf
varf + stepf
Else
varf - stepf
EndIf
EndMacro
Macro Nextf()
Wend
EndMacro
Debug "ForF(a.f, 1.0, 1.2, 0.05)"
ForF(a.f, 1.0, 1.2, 0.05)
Debug "a: " + a
Debug "ForF(a.f, 1.2, 1.0, 0.05)"
ForF(b.f, 1.2, 1.0, 0.05)
Debug "b: " + b
NextF()
Debug "-------------------------"
NextF()
or
Code: Select all
Macro ForF(varf,startf,endf,stepf)
If startf < endf
varf = startf - stepf
Else
varf = startf + stepf
EndIf
While (startf < endf And varf < (endf - stepf * 0.5)) Or (startf > endf And varf > (endf + stepf * 0.5))
If startf < endf
varf + stepf
Else
varf - stepf
EndIf
EndMacro
Macro Nextf()
Wend
EndMacro
Debug "ForF(a.f, 1.0, 1.2, 0.05)"
ForF(a.f, 1.0, 1.2, 0.05)
Debug "a: " + a
Debug "ForF(a.f, 1.2, 1.0, 0.05)"
ForF(b.f, 1.2, 1.0, 0.05)
Debug "b: " + b
NextF()
Debug "-------------------------"
NextF()
P.S. Best result with double
Code: Select all
Debug "ForF(a.d, 1.0, 1.2, 0.05)"
ForF(a.d, 1.0, 1.2, 0.05)
Debug "a: " + a
Debug "ForF(a.d, 1.2, 1.0, 0.05)"
ForF(b.d, 1.2, 1.0, 0.05)
Debug "b: " + b
NextF()
Debug "-------------------------"
NextF()
GT

Re: For/Next with [float] variable Step
Posted: Tue Nov 05, 2013 5:31 pm
by blueznl
Call me stupid (hey, I can handle that

) but isn't the regular While / Wend not good enough? And it is very basic like!
a.f = 1.0
while a < 10
...
...
a = a+.1
wend