For/Next with [float] variable Step

Share your advanced PureBasic knowledge/code with the community.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

For/Next with [float] variable Step

Post 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! :D

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()
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
Thorium
Addict
Addict
Posts: 1305
Joined: Sat Aug 15, 2009 6:59 pm

Re: For/Next with [float] variable Step

Post 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()
User avatar
Demivec
Addict
Addict
Posts: 4270
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: For/Next with [float] variable Step

Post 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.
Last edited by Demivec on Wed Sep 18, 2013 1:28 am, edited 1 time in total.
BorisTheOld
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Apr 24, 2012 5:08 pm
Location: Ontario, Canada

Re: For/Next with [float] variable Step

Post 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
For ten years Caesar ruled with an iron hand, then with a wooden foot, and finally with a piece of string.
~ Spike Milligan
Thorium
Addict
Addict
Posts: 1305
Joined: Sat Aug 15, 2009 6:59 pm

Re: For/Next with [float] variable Step

Post by Thorium »

It works as long as you dont use variables for start and finish.
jassing
Addict
Addict
Posts: 1885
Joined: Wed Feb 17, 2010 12:00 am

Re: For/Next with [float] variable Step

Post 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.
BorisTheOld
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Apr 24, 2012 5:08 pm
Location: Ontario, Canada

Re: For/Next with [float] variable Step

Post 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.
For ten years Caesar ruled with an iron hand, then with a wooden foot, and finally with a piece of string.
~ Spike Milligan
User avatar
minimy
Enthusiast
Enthusiast
Posts: 632
Joined: Mon Jul 08, 2013 8:43 pm
Location: off world

Re: For/Next with [float] variable Step

Post 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
If translation=Error: reply="Sorry, Im Spanish": Endif
User avatar
Demivec
Addict
Addict
Posts: 4270
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: For/Next with [float] variable Step

Post 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.
User avatar
mk-soft
Always Here
Always Here
Posts: 6252
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: For/Next with [float] variable Step

Post 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 :wink:
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Re: For/Next with [float] variable Step

Post by blueznl »

Call me stupid (hey, I can handle that 8) ) but isn't the regular While / Wend not good enough? And it is very basic like! :lol:
a.f = 1.0
while a < 10
...
...
a = a+.1
wend
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Post Reply