For Next Step
-
- Always Here
- Posts: 6426
- Joined: Fri Oct 23, 2009 2:33 am
- Location: Wales, UK
- Contact:
For Next Step
The Step of a For Next loop is limited to an integer constant. There are occasions where an integer is required instead of a constant.
Edit: Yes, I am using another loop type instead but For Next is more elegant.
Edit: Yes, I am using another loop type instead but For Next is more elegant.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
If it sounds simple, you have not grasped the complexity.
Re: For Next Step
SPAM
STEP Variable !
For : Next : Step with decimals
Step in For loop to accept an expression
for-next
STEP Value.l
...
Search

STEP Variable !
For : Next : Step with decimals
Step in For loop to accept an expression
for-next
STEP Value.l
...

PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Re: For Next Step
Already requested ... yes.STARGÅTE wrote:SPAM![]()
But SPAM ?

"Have you tried turning it off and on again ?"
A little PureBasic review
A little PureBasic review
Re: For Next Step
Why not create a ForD, like we have StrD and ValD, for example?
This preserves the original For - Next statement, to maintain high speed.
I second the idea to create a For/Next statement that uses decimals (as well the Step), as it makes programming sometimes much easier.
This preserves the original For - Next statement, to maintain high speed.
I second the idea to create a For/Next statement that uses decimals (as well the Step), as it makes programming sometimes much easier.
- Windows 11 Home 64-bit
- PureBasic 6.10 LTS (x64)
- 64 Gb RAM
- 13th Gen Intel(R) Core(TM) i9-13900K 3.00 GHz
- 5K monitor with DPI @ 200%
- PureBasic 6.10 LTS (x64)
- 64 Gb RAM
- 13th Gen Intel(R) Core(TM) i9-13900K 3.00 GHz
- 5K monitor with DPI @ 200%
Re: For Next Step
My reading of the original post is not for floating point steps, but variable steps.
for i = x to y step z where z is an actual expression, not a constant.
I can see how this could be useful in some circumstances.
for i = x to y step z where z is an actual expression, not a constant.
I can see how this could be useful in some circumstances.
Re: For Next Step
Yes, very useful in many situations. While I haven't used it yet in PB, I'm surprised to see PB doesn't allow it.
Here are a couple macros that will work with any var type and any Step. They are the same as what For Next does, but without restriction. The only drawback is that since you can't put a block of code in a macro call, you have to reference the Var and Step in the ForEnd, not the ForStart.
Here are a couple macros that will work with any var type and any Step. They are the same as what For Next does, but without restriction. The only drawback is that since you can't put a block of code in a macro call, you have to reference the Var and Step in the ForEnd, not the ForStart.
Code: Select all
Macro ForStart(Var, starting, ending)
Var = starting
While Var <= ending
EndMacro
Macro ForEnd(Var, increment)
Var = Var + increment
Wend
EndMacro
Macro ForStartDec(Var, starting, ending)
Var = starting
While Var >= ending
EndMacro
Macro ForEndDec(Var, increment)
Var = Var - increment
Wend
EndMacro
; Incrementing sample with Float:
x.f
ForStart(x, 1, 3.5)
Debug x
ForEnd(x, 0.5)
Debug "last x " + Str(x)
; Decrementing sample with variable Step:
i.f
a.i = 2
ForStartDec(i, 12, 2)
Debug i
ForEndDec(i, a)
Debug "last i " + Str(i)
Re: For Next Step
@Tenaja,
I was very interested in your Macros in attempting to create a For-Next-Step with the same sequence and logic.
I have studied the drawback you mentioned.
Well, I have rewritten the Macros based on your idea.
I have tested it superficially, and it seems to work... Any bug or comment is welcome!
I was very interested in your Macros in attempting to create a For-Next-Step with the same sequence and logic.
I have studied the drawback you mentioned.
Well, I have rewritten the Macros based on your idea.
I have tested it superficially, and it seems to work... Any bug or comment is welcome!
Code: Select all
;==================================================================
Macro Loop(Var,Starting,Ending,Increment=1)
*Start#Var=AllocateMemory(9)
PokeD(*Start#Var,Starting)
*End#Var=AllocateMemory(9)
PokeD(*End#Var,Ending)
*Incr#Var=AllocateMemory(9)
PokeD(*Incr#Var,Increment)
Var=Starting
Repeat
EndMacro
;==================================================================
Macro EndLoop(Var)
Starting#Var.d=PeekD(*Start#Var)
Ending#Var.d=PeekD(*End#Var)
Increment#Var.d=PeekD(*Incr#Var)
Var+Increment#Var
Qend.d=Starting#Var+((Ending#Var-Starting#Var)/Increment#Var)*Increment#Var; calculate the number of steps to know the real destination value
a.d=Var : b.d=Qend
If Increment#Var<0; negative increment
a.d=Qend : b.d=Var; swap current var & real ending
EndIf
Until a>b; if increment was negative, we had to swap the variables, because we cannot swap the direction of Until
FreeMemory(*Incr#Var)
FreeMemory(*Start#Var)
FreeMemory(*End#Var)
EndMacro
;==================================================================
; Example
Loop(i.d,1,5.5,1.5)
Loop(j.d,16,4,-3.5)
Debug "("+StrD(i,2)+", "+StrD(j,2)+")"
EndLoop(j)
EndLoop(i)
Debug "last i = " + StrD(i)
Debug "last j = " + StrD(j)
;==================================================================
- Windows 11 Home 64-bit
- PureBasic 6.10 LTS (x64)
- 64 Gb RAM
- 13th Gen Intel(R) Core(TM) i9-13900K 3.00 GHz
- 5K monitor with DPI @ 200%
- PureBasic 6.10 LTS (x64)
- 64 Gb RAM
- 13th Gen Intel(R) Core(TM) i9-13900K 3.00 GHz
- 5K monitor with DPI @ 200%
Re: For Next Step
Charvista, in general, I like your use of alloc to make them nestable. On the other hand, have you looked at the asm? It's LOOOOOOONG! So maybe not great for time sensitive code. This is your sample, with no edits:
That's 25 instructions to get started, and 49 at the end (minus a few labels). That's a lot of overhead for a loop...mine is 10 instructions total (plus labels):
Code: Select all
;
; PureBasic 4.60 (Windows - x86) generated code
;
; (c) 2011 Fantaisie Software
;
; The header must remain intact for Re-Assembly
;
; Memory
; :System
; KERNEL32
; :Import
;
format MS COFF
;
;
extrn _PB_AllocateMemory@4
extrn _PB_FreeMemory@4
extrn _PB_FreeMemorys@0
extrn _PB_InitMemory@0
extrn _PB_PeekD@4
extrn _PB_PokeD@12
extrn _ExitProcess@4
extrn _GetModuleHandleA@4
extrn _HeapCreate@12
extrn _HeapDestroy@4
extrn _memset
public _PB_Instance
public _PB_ExecutableType
public _PB_OpenGLSubsystem
public _PB_MemoryBase
public PB_Instance
public PB_MemoryBase
public _PB_EndFunctions
macro pb_public symbol
{
public _#symbol
public symbol
_#symbol:
symbol:
}
macro pb_align value { rb (value-1) - ($-_PB_DataSection + value-1) mod value }
macro pb_bssalign value { rb (value-1) - ($-_PB_BSSSection + value-1) mod value }
public PureBasicStart
;
section '.code' code readable executable align 8
;
;
PureBasicStart:
;
PUSH dword I_BSSEnd-I_BSSStart
PUSH dword 0
PUSH dword I_BSSStart
CALL _memset
ADD esp,12
PUSH dword 0
CALL _GetModuleHandleA@4
MOV [_PB_Instance],eax
PUSH dword 0
PUSH dword 4096
PUSH dword 0
CALL _HeapCreate@12
MOV [PB_MemoryBase],eax
CALL _PB_InitMemory@0
;
;==================================================================
; Macro Loop(Var,Starting,Ending,Increment=1)
;==================================================================
; Macro EndLoop(Var)
;==================================================================
; Example
; Loop(i.d,1,5.5,1.5)
PUSH dword 9
CALL _PB_AllocateMemory@4
MOV dword [p_Starti],eax
FLD qword [D1]
SUB esp,8
FSTP qword [esp]
PUSH dword [p_Starti]
CALL _PB_PokeD@12
PUSH dword 9
CALL _PB_AllocateMemory@4
MOV dword [p_Endi],eax
FLD qword [D2]
SUB esp,8
FSTP qword [esp]
PUSH dword [p_Endi]
CALL _PB_PokeD@12
PUSH dword 9
CALL _PB_AllocateMemory@4
MOV dword [p_Incri],eax
FLD qword [D3]
SUB esp,8
FSTP qword [esp]
PUSH dword [p_Incri]
CALL _PB_PokeD@12
FLD qword [D1]
FSTP qword [v_i]
_Repeat1:
; Loop(j.d,16,4,-3.5)
PUSH dword 9
CALL _PB_AllocateMemory@4
MOV dword [p_Startj],eax
FLD qword [D4]
SUB esp,8
FSTP qword [esp]
PUSH dword [p_Startj]
CALL _PB_PokeD@12
PUSH dword 9
CALL _PB_AllocateMemory@4
MOV dword [p_Endj],eax
FLD qword [D5]
SUB esp,8
FSTP qword [esp]
PUSH dword [p_Endj]
CALL _PB_PokeD@12
PUSH dword 9
CALL _PB_AllocateMemory@4
MOV dword [p_Incrj],eax
FLD qword [D6]
SUB esp,8
FSTP qword [esp]
PUSH dword [p_Incrj]
CALL _PB_PokeD@12
FLD qword [D4]
FSTP qword [v_j]
_Repeat2:
; Debug "("+StrD(i,2)+", "+StrD(j,2)+")"
; EndLoop(j)
PUSH dword [p_Startj]
CALL _PB_PeekD@4
FSTP qword [v_Startingj]
PUSH dword [p_Endj]
CALL _PB_PeekD@4
FSTP qword [v_Endingj]
PUSH dword [p_Incrj]
CALL _PB_PeekD@4
FSTP qword [v_Incrementj]
FLD qword [v_j]
FADD qword [v_Incrementj]
FADD qword [D7]
FSTP qword [v_j]
FLD qword [v_Startingj]
FLD qword [v_Endingj]
FSUB qword [v_Startingj]
FADD qword [D7]
FDIV qword [v_Incrementj]
FMUL qword [v_Incrementj]
FADDP st1,st0
FADD qword [D7]
FSTP qword [v_Qend]
FLD qword [v_j]
FSTP qword [v_a]
FLD qword [v_Qend]
FSTP qword [v_b]
FLD qword [v_Incrementj]
FCOMP qword [D7]
FNSTSW ax
TEST ah,1h
JE _EndIf4
FLD qword [v_Qend]
FSTP qword [v_a]
FLD qword [v_j]
FSTP qword [v_b]
_EndIf4:
FLD qword [v_a]
FLD qword [v_b]
FCOMPP
FNSTSW ax
TEST ah,1h
JE _Repeat2
_Until2:
PUSH dword [p_Incrj]
CALL _PB_FreeMemory@4
PUSH dword [p_Startj]
CALL _PB_FreeMemory@4
PUSH dword [p_Endj]
CALL _PB_FreeMemory@4
; EndLoop(i)
PUSH dword [p_Starti]
CALL _PB_PeekD@4
FSTP qword [v_Startingi]
PUSH dword [p_Endi]
CALL _PB_PeekD@4
FSTP qword [v_Endingi]
PUSH dword [p_Incri]
CALL _PB_PeekD@4
FSTP qword [v_Incrementi]
FLD qword [v_i]
FADD qword [v_Incrementi]
FADD qword [D7]
FSTP qword [v_i]
FLD qword [v_Startingi]
FLD qword [v_Endingi]
FSUB qword [v_Startingi]
FADD qword [D7]
FDIV qword [v_Incrementi]
FMUL qword [v_Incrementi]
FADDP st1,st0
FADD qword [D7]
FSTP qword [v_Qend]
FLD qword [v_i]
FSTP qword [v_a]
FLD qword [v_Qend]
FSTP qword [v_b]
FLD qword [v_Incrementi]
FCOMP qword [D7]
FNSTSW ax
TEST ah,1h
JE _EndIf6
FLD qword [v_Qend]
FSTP qword [v_a]
FLD qword [v_i]
FSTP qword [v_b]
_EndIf6:
FLD qword [v_a]
FLD qword [v_b]
FCOMPP
FNSTSW ax
TEST ah,1h
JE _Repeat1
_Until1:
PUSH dword [p_Incri]
CALL _PB_FreeMemory@4
PUSH dword [p_Starti]
CALL _PB_FreeMemory@4
PUSH dword [p_Endi]
CALL _PB_FreeMemory@4
;
; Debug "last i = " + StrD(i)
; Debug "last j = " + StrD(j)
;==================================================================
_PB_EOP_NoValue:
PUSH dword 0
_PB_EOP:
CALL _PB_EndFunctions
PUSH dword [PB_MemoryBase]
CALL _HeapDestroy@4
CALL _ExitProcess@4
_PB_EndFunctions:
CALL _PB_FreeMemorys@0
RET
;
;
section '.data' data readable writeable
;
_PB_DataSection:
_PB_OpenGLSubsystem: db 0
pb_public PB_DEBUGGER_LineNumber
dd -1
pb_public PB_DEBUGGER_IncludedFiles
dd 0
pb_public PB_DEBUGGER_FileName
db 0
_PB_ExecutableType: dd 0
align 4
D1: dd 0,1072693248
D2: dd 0,1075183616
D3: dd 0,1073217536
D4: dd 0,1076887552
D5: dd 0,1074790400
D6: dd 0,-1072955392
D7: dd 0,0
align 4
s_s:
dd 0
dd -1
align 4
;
section '.bss' readable writeable
_PB_BSSSection:
align 4
;
I_BSSStart:
_PB_MemoryBase:
PB_MemoryBase: rd 1
_PB_Instance:
PB_Instance: rd 1
;
align 4
v_i rq 1
v_j rq 1
v_Startingj rq 1
v_Endingj rq 1
v_Incrementj rq 1
v_Qend rq 1
v_a rq 1
v_b rq 1
v_Startingi rq 1
v_Endingi rq 1
v_Incrementi rq 1
PB_DataPointer rd 1
p_Starti rd 1
p_Endi rd 1
p_Incri rd 1
p_Startj rd 1
p_Endj rd 1
p_Incrj rd 1
align 4
align 4
align 4
align 4
I_BSSEnd:
section '.data' data readable writeable
SYS_EndDataSection:
Code: Select all
; ForStart(x, 1, 3.5)
MOV dword [v_x],1065353216
_While1:
FLD dword [v_x]
FCOMP dword [F1]
FNSTSW ax
TEST ah,41h
JE _Wend1
; Debug x
; ForEnd(x, 0.5)
FLD dword [v_x]
FADD dword [F2]
FSTP dword [v_x]
JMP _While1
_Wend1:
;
; Debug "last x " + Str(x)
Re: For Next Step
I was thinking of your loops...the same thing can be accomplished with Push and Pop. That will save most of the code space.
Re: For Next Step
Maybe like this...
Code: Select all
Macro ForD(StartD)
StartD
!Loop@:
EndMacro
Macro NextD(StartD, StopD, StepD)
StartD + StepD
If StartD < StopD
!jmp Loop@
EndIf
EndMacro
ForD(i.d = 0)
Debug i.d
NextD(i, 8, 0.5)
Last edited by djes on Thu Feb 23, 2012 3:51 pm, edited 2 times in total.
Re: For Next Step
@Tenaja & @djes & @All
The problem is that I have never learned Assembler, so I have no idea how to make it shorter. I am thinking purely in PureBasic. I can only understand that the complexity of my code can be time consuming at runtime, but I made some tests and I think that the speed is still high enough, as calculations with doubles are always slower than with integers.
@djes: the macro you made has a problem: in nested loops, it cannot be used again, because the symbol is already defined. (As this is asm, I have no clue what that means).
The problem is that I have never learned Assembler, so I have no idea how to make it shorter. I am thinking purely in PureBasic. I can only understand that the complexity of my code can be time consuming at runtime, but I made some tests and I think that the speed is still high enough, as calculations with doubles are always slower than with integers.
@djes: the macro you made has a problem: in nested loops, it cannot be used again, because the symbol is already defined. (As this is asm, I have no clue what that means).
Code: Select all
;==================================================================
Macro Loop(Var,Starting,Ending,Increment=1)
*Start#Var=AllocateMemory(9)
PokeD(*Start#Var,Starting)
*End#Var=AllocateMemory(9)
PokeD(*End#Var,Ending)
*Incr#Var=AllocateMemory(9)
PokeD(*Incr#Var,Increment)
Var=Starting
Repeat
EndMacro
;==================================================================
Macro EndLoop(Var)
Starting#Var.d=PeekD(*Start#Var)
Ending#Var.d=PeekD(*End#Var)
Increment#Var.d=PeekD(*Incr#Var)
Var+Increment#Var
Qend.d=Starting#Var+((Ending#Var-Starting#Var)/Increment#Var)*Increment#Var; calculate the number of steps to know the real destination value
a.d=Var : b.d=Qend
If Increment#Var<0; negative increment
a.d=Qend : b.d=Var; swap current var & real ending
EndIf
Until a>b; if increment was negative, we had to swap the variables, because we cannot swap the direction of Until
FreeMemory(*Incr#Var)
FreeMemory(*Start#Var)
FreeMemory(*End#Var)
EndMacro
;==================================================================
Macro ForD(StartD)
!Loop@:
EndMacro
;==================================================================
Macro NextD(StartD, StopD, StepD)
StartD + StepD
If StartD < StopD
!jmp Loop@
EndIf
EndMacro
;==================================================================
; Example
Debug "Please wait until loops are finished!............."
DisableDebugger
StartTime = ElapsedMilliseconds()
Loop(i.d,1,100000,0.75)
Loop(j.d,6000,-4000,-3.5)
;Debug "("+StrD(i,2)+", "+StrD(j,2)+")"
EndLoop(j)
EndLoop(i)
ElapsedTime1 = ElapsedMilliseconds()-StartTime
; StartTime = ElapsedMilliseconds()
; ForD(a.d = 1)
; ForD(b.d = 6000)
; ;...
; NextD(b, -4000,-3.5)
; NextD(a, 100000, 0.75)
; ElapsedTime2 = ElapsedMilliseconds()-StartTime
StartTime = ElapsedMilliseconds()
For k=1 To 100000 Step 1
For l=6000 To -4000 Step -3
;Debug "("+StrD(k,2)+", "+StrD(l,2)+")"
Next l
Next k
ElapsedTime3 = ElapsedMilliseconds()-StartTime
EnableDebugger
Debug ElapsedTime1
;Debug ElapsedTime2
Debug ElapsedTime3
;==================================================================
- Windows 11 Home 64-bit
- PureBasic 6.10 LTS (x64)
- 64 Gb RAM
- 13th Gen Intel(R) Core(TM) i9-13900K 3.00 GHz
- 5K monitor with DPI @ 200%
- PureBasic 6.10 LTS (x64)
- 64 Gb RAM
- 13th Gen Intel(R) Core(TM) i9-13900K 3.00 GHz
- 5K monitor with DPI @ 200%
Re: For Next Step
I don't see any advantage of a for / next with variable step over a while / wend or repeat / until. In fact, a while / wend leaves IMHO better readable code.
Not being able to use a quad in a for / next is indeed a bit silly, though I've never need it thus far
Not being able to use a quad in a for / next is indeed a bit silly, though I've never need it thus far

( 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... )
( The path to enlightenment and the PureBasic Survival Guide right here... )
Re: For Next Step
@blueznl
Let's return the problem: What's the advantage of For/Next over While/Wend or Repeat/Until ?
If there is one, even a small one, then the same advantage may apply to the variable step (and doubles) as well.
To me, the big advantage is that I tell the program the fixed range and the step to the loop in one single line before it begins.
Let's return the problem: What's the advantage of For/Next over While/Wend or Repeat/Until ?
If there is one, even a small one, then the same advantage may apply to the variable step (and doubles) as well.

To me, the big advantage is that I tell the program the fixed range and the step to the loop in one single line before it begins.
- Windows 11 Home 64-bit
- PureBasic 6.10 LTS (x64)
- 64 Gb RAM
- 13th Gen Intel(R) Core(TM) i9-13900K 3.00 GHz
- 5K monitor with DPI @ 200%
- PureBasic 6.10 LTS (x64)
- 64 Gb RAM
- 13th Gen Intel(R) Core(TM) i9-13900K 3.00 GHz
- 5K monitor with DPI @ 200%
Re: For Next Step
Yes, I can see that advantage of For / Next, and that does make sense. However, when doing fancy stuff (like changing the step parameter) it actually does make sense to switch to While / Wend, as you're no longer doing something simple and straightforward. In fact, you're changing the step parameter, something not obvious from the first For / Next call.
So, I beg to disagree with you
So, I beg to disagree with you

( 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... )
( The path to enlightenment and the PureBasic Survival Guide right here... )
Re: For Next Step
The way PB handles the For/Next loop, the ONLY advantage is readability. It compiles longer, and executes slower than a repeat/until or while/wend.charvista wrote:To me, the big advantage is that I tell the program the fixed range and the step to the loop in one single line before it begins.
The reason is the same as what you like about it. PB parses the loop sequentially, and does NOT reorder anything. Therefore, the assignment is made, the test is performed, the increment is Jumped over (wasted time), the loop is run, then at Next, it Jumps to the increment, after which it Jumps to the test, and then it either jumps to the loop code or out of the loop.
All of those jumps make the For-Next loop the most inefficient loop you can use--both in code space and execution time. But it is easy to code and very readable, so if speed is not an issue, all is good.
Oh, yeah...only if your increment is a constant integer, you are good.