Recent

Poll

I want for-loops with custom step widths (plural!).

false
24 (42.1%)
true
27 (47.4%)
42
6 (10.5%)

Total Members Voted: 57

Author Topic: for loop with custom step width (esp. ≠ 1)  (Read 51405 times)

Thaddy

  • Hero Member
  • *****
  • Posts: 14377
  • Sensorship about opinions does not belong here.
Re: for loop with custom step width (esp. ≠ 1)
« Reply #15 on: December 19, 2016, 08:12:46 am »
The counter in for loop cannot be altered by user unlike C/C++ for loop.

Oh? what's this then ;) :
Code: Pascal  [Select][+][-]
  1.  
  2. var
  3.   i:integer;
  4. begin
  5.   for i := 0 to 99 do
  6.   begin
  7.     inc(PInteger(@i)^);
  8.     writeln(i);
  9.   end;
  10. end.

That's a trick I published as far back as 1997 in UNDU btw.
Unlike [edit older versions of ] FPC, Delphi never allowed it to modify the index directly.

In a cheeky way here 's the FPC code ;) :) ;) Given i = index.
Code: Pascal  [Select][+][-]
  1. {$Macro on}{$Define step2:=inc(PInteger(@i)^)}
  2. var
  3.   i:integer;
  4. begin
  5.   for i := 0 to 99 do
  6.   begin
  7.     step2;
  8.     writeln(i);
  9.   end;
  10. end.


Don't use it, though: if you use it in the wrong place it becomes an endless loop... (change 99 to 100 is enough)

This is merely to demonstrate that you CAN change the index of a for loop

A safe way to do loop steps  is:
Code: Pascal  [Select][+][-]
  1. {$Macro on}{$define step2 := if i mod 2 <> 0 then continue}  //  modulo step, note: any step desired
  2. var
  3.   i:integer;
  4. begin
  5.   for i := 0 to 100 do
  6.   begin
  7.     step2;
  8.     writeln(i);
  9.   end;
  10. end.

« Last Edit: December 19, 2016, 09:57:13 am by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

Deepaak

  • Sr. Member
  • ****
  • Posts: 454
Re: for loop with custom step width (esp. ≠ 1)
« Reply #16 on: December 19, 2016, 09:14:43 am »

Oh? what's this then ;) :
Code: Pascal  [Select][+][-]
  1.  
  2. var
  3.   i:integer;
  4. begin
  5.   for i := 0 to 99 do
  6.   begin
  7.     inc(PInteger(@i)^);
  8.     writeln(i);
  9.   end;
  10. end.

That's a trick I published as far back as 1997 in UNDU btw.



That's cool, but i had tested your sample but didn't received the desired result. Please have a look

Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. var
  4.   i:integer;
  5. begin
  6.   for i := 0 to 100 do
  7.   begin
  8.  
  9.  
  10.     inc(PInteger(@i)^ ,10);
  11.     writeln(i);
  12.   end;
  13.   readln;
  14.  
  15.   begin
  16.     i := 0;
  17.     while i <= 100 do
  18.     begin
  19.       WriteLn('i: ', i);
  20.      Inc(i,10);
  21.     end;
  22.   end;
  23.  
  24.   readln;
  25.  
  26. end.        
  27.  

Code: Pascal  [Select][+][-]
  1. For Loop Start
  2. 10
  3. 21
  4. 32
  5. 43
  6. 54
  7. 65
  8. 76
  9. 87
  10. 98
  11. 109
  12. For Loop End.
  13.  
  14. While Loop Start
  15. i: 0
  16. i: 10
  17. i: 20
  18. i: 30
  19. i: 40
  20. i: 50
  21. i: 60
  22. i: 70
  23. i: 80
  24. i: 90
  25. i: 100
  26. While Loop End
  27.  

Do i have missed something.

Update..

You are incrementing the address content,  instead of i. so on first run when i =0 you are incrementing +1 now the value of i which is zero is incremented to 1. OK. But when control passes to for it finds the value of i=1 instead of zero. So it increments I=2 instead of 1. On next execution you increment I, from I=2 to I=3.

Waiting for your input. If am i wrong please guide.
« Last Edit: December 19, 2016, 09:33:57 am by Deepaak »
Holiday season is online now. :-)

Thaddy

  • Hero Member
  • *****
  • Posts: 14377
  • Sensorship about opinions does not belong here.
Re: for loop with custom step width (esp. ≠ 1)
« Reply #17 on: December 19, 2016, 09:26:26 am »
index will always step 1 by itself so if you want to step 10, you increment the index by 9. Buy one get 9 for free ;)
Code: Text  [Select][+][-]
  1. var i:integer;
  2. begin
  3.   for i := 0 to 100 do
  4.   begin
  5.      writeln(i);
  6.      inc(PInteger(@i)^ ,9);
  7.  end;
  8. end.
  9. 0
  10. 10
  11. 20
  12. 30
  13. 40
  14. 50
  15. 60
  16. 70
  17. 80
  18. 90
  19. 100
  20.  
  21.  

But plz use the modulo trick instead of the pointer trick: that's safe!
« Last Edit: December 19, 2016, 09:37:48 am by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

Deepaak

  • Sr. Member
  • ****
  • Posts: 454
Re: for loop with custom step width (esp. ≠ 1)
« Reply #18 on: December 19, 2016, 09:37:34 am »
index will always step 1 by itself so if you want to step 10, you increment the index by 9.
Code: Text  [Select][+][-]
  1. var i:integer;
  2. begin
  3.   for i := 0 to 100 do
  4.   begin
  5.      writeln(i);
  6.      inc(PInteger(@i)^ ,9);
  7.  end;
  8. end.
  9. 0
  10. 10
  11. 20
  12. 30
  13. 40
  14. 50
  15. 60
  16. 70
  17. 80
  18. 90
  19. 100
  20.  
  21.  

But plz use the modulo trick instead of the pointer trick: that's safe!

Thanks on your input. If i am not wrong pointer trick for tutorial is good but for real world program it may creates problems. Secondly, i want to ask if modulo trick is good to go in real world applications, or one should consider using while or repeat loops. Thanks once again  :)
« Last Edit: December 19, 2016, 09:52:35 am by Deepaak »
Holiday season is online now. :-)

Thaddy

  • Hero Member
  • *****
  • Posts: 14377
  • Sensorship about opinions does not belong here.
Re: for loop with custom step width (esp. ≠ 1)
« Reply #19 on: December 19, 2016, 10:42:53 am »
The modulo trick is safe to use in production code as long as you are aware how modulo works. It can also have minor side effects.
Also note that you can only use it like for 0 to X do step pseudo syntax, so the step has to be the first in the begin end block.
And the starting step - if not from zero - should be modulo x = 0;
Also note that the pointer trick is much faster, so if speed is an issue (like in gaming) you may want to use the pointer trick after all, but it has major side effects.
But defining a couple of macro's like:
Code: Pascal  [Select][+][-]
  1. {$macro on}
  2. {$define step2 := if i mod 2 <> 0 then continue}
  3. {$define step3 := if i mod 3 <> 0 then continue}
  4. {$define step4 := if i mod 4 <> 0 then continue}
  5. --- etc
  6. {$define step10 := if i mod 10 <> 0 then continue}
  7.  
will go a long way ;) and makes readable code
Code: Pascal  [Select][+][-]
  1.   for i := 0 to 100 do
  2.   begin
  3.      stepx;
  4.      ...
  5.   end;
« Last Edit: December 19, 2016, 10:53:24 am by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

Josh

  • Hero Member
  • *****
  • Posts: 1274
Re: for loop with custom step width (esp. ≠ 1)
« Reply #20 on: December 19, 2016, 11:00:21 am »
Hi

Just spotted the topic; some really good snippets of code and tricks to accomplish a step function; if for some reason your stuck with the For Loop then I like the MOD idea for its simplicity; I do agree though it is not the best for the scenario in question and the standard While and Repeat Loops are far more suited to solve the problem in a standard way.

Code: [Select]
start_value=2;
end_value:=99;
step_value=3;
for i:= start_value to end_value do
begin
  if ((i-start_value) mod step_value)=0 then
  begin
     // do your stuff
  end;
end;


Just curious as to purpose of a poll to add it to FPC only, as this would make it non compatible with earlier FPC and non compatible with pascal standards and afaik all other pascal dialects. SO even if it were added; it should not be used if you wish the code to used anywhere else.

The best way to get accurate information on the forum is to post something wrong and wait for corrections.

Thaddy

  • Hero Member
  • *****
  • Posts: 14377
  • Sensorship about opinions does not belong here.
Re: for loop with custom step width (esp. ≠ 1)
« Reply #21 on: December 19, 2016, 11:16:52 am »
The reason I did not include your way of "modding" is that it can not be captured in a single line macro ;) - you will need two.
Usually I only prefer this type of trickery code over while and repeat when I am translating from another language that does support steps.
I use it as a quick way to have the guaranteed same behavior and will probably later choose a more appropriate Pascal Language construct/syntax.
« Last Edit: December 19, 2016, 11:26:15 am by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: for loop with custom step width (esp. ≠ 1)
« Reply #22 on: December 19, 2016, 02:13:08 pm »
Nice approach Thaddy, in your example deceiving the compiler for manipulating the iterator  :)

I tried using the absolute modifier but unfortunately the compiler picked up on that.

Indeed, i often find myself in similar situation when porting code from another language into Pascal, in which case i really miss the possibility to increase the iterator with a certain step size.

The problem with Thaddy's approach is the same as with the while loop solution: in porting i often forget to update the iterator, especially when several loops are nested and/or original routines are lengthy.

For that reason alone i vote yes, although i realize i voted only for this specific purpose.

ASerge

  • Hero Member
  • *****
  • Posts: 2246
Re: for loop with custom step width (esp. ≠ 1)
« Reply #23 on: December 19, 2016, 03:10:31 pm »
Compare
Code: Pascal  [Select][+][-]
  1. for i := 0 to 100 do
  2. begin
  3.   Some(i);
  4.   Inc(PInteger(@i)^, 9);
  5. end;
and
Code: Pascal  [Select][+][-]
  1. i := 0;
  2. while i <= 100 do
  3. begin
  4.   Some(i);
  5.   Inc(i, 10);
  6. end;
The second code is better because:
1. It is more clear, no hidden features.
2. It meets the requirements of language, i.e., will not break in the next release.
3. It is optimized by the compiler, i.e. more efficient.
My vote: no

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11455
  • FPC developer.
Re: for loop with custom step width (esp. ≠ 1)
« Reply #24 on: December 19, 2016, 03:44:59 pm »
A maybe less dirty workaround would be to use an iterator.

something (sketchy only) like:

Code: Pascal  [Select][+][-]
  1. {$mode delphi}
  2. type  
  3.  
  4.       RangeWithStep = record
  5.                             fcur,ffrom,fto,fstep:integer;
  6.                             constructor create (from,xto,step:integer);
  7.                             function getenumerator: RangeWithStep; inline;
  8.                             function MoveNext:Boolean; inline;
  9.                             property Current:integer read fcur;
  10.                           end;
  11.  
  12. constructor RangeWithStep.create (from,xto,step:integer);
  13. begin
  14.  ffrom:=from; fto:=xto; fstep:=step;   fcur:=0;
  15. end;
  16.  
  17. function RangeWithStep.getenumerator: RangeWithStep;
  18. begin
  19.  fcur:=0;
  20.  result:=self; // (or @fcur^?)
  21. end;
  22.  
  23. function RangeWithStep.MoveNext:Boolean;
  24. begin
  25.  inc(fcur,fstep); // still risky wrt range/overflow checks?
  26.  result:=fcur<=fto;
  27. end;
  28.  
  29.  
  30. var x  : integer; // al
  31. begin
  32.   for x in  RangeWithStep.Create(1,100,2) do
  33.     writeln(x);
  34. end.

The generated assembler code for an iteration is not real HPC, but still not too bad (for y:=y+x instead of writeln(x)

Code: Pascal  [Select][+][-]
  1. .Lj10:
  2.         movl    -16(%ebp),%edx
  3. # [34] y:=y+x;
  4.         leal    (%ebx,%edx),%eax
  5.         movl    %eax,%ebx
  6. .Lj11:
  7.         movl    -4(%ebp),%eax
  8.         addl    %eax,-16(%ebp)
  9.         movl    -16(%ebp),%eax
  10.         cmpl    -8(%ebp),%eax
  11.         setleb  %al
  12.         testb   %al,%al
  13.         jne     .Lj10
  14.  
« Last Edit: December 19, 2016, 03:48:25 pm by marcov »

Thaddy

  • Hero Member
  • *****
  • Posts: 14377
  • Sensorship about opinions does not belong here.
Re: for loop with custom step width (esp. ≠ 1)
« Reply #25 on: December 19, 2016, 05:15:53 pm »
Very elegant.
But zero step is missed somehow.

BTW my initial code was just teasing, as I explained..
« Last Edit: December 19, 2016, 05:37:02 pm by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

Kays

  • Hero Member
  • *****
  • Posts: 576
  • Whasup!?
    • KaiBurghardt.de
Re: for loop with custom step width (esp. ≠ 1)
« Reply #26 on: December 19, 2016, 07:14:27 pm »
[…] purpose of a poll […]
I was bored and things really started to go beyond scope. I am not looking at anyone (mumbling) Thaddy but from my perspective this case is closed.

For the record: I was asking for for-loops with custom step widths.
I was _not_ asking for dozens of alternative ways, how to achieve this. Could you go for this (hacky, “I'm the pro”, manner) to some corner else? Thank you.
Yours Sincerely
Kai Burghardt

Thaddy

  • Hero Member
  • *****
  • Posts: 14377
  • Sensorship about opinions does not belong here.
Re: for loop with custom step width (esp. ≠ 1)
« Reply #27 on: December 19, 2016, 07:52:12 pm »
I wasn't hacky. I was frankly rather well balanced.
I merely made two points one of which was not only correct, but also safe:
- 1. You can, contrary to what was written by DeePaak, modify the index counter. That's just informative.
- 2. I provide a macro solution (the one with the modulo, as per my comments) that provides custom steps in a clean and safe way. That was what you asked and certainly not a hacky solution. Unless you disqualify macro's in general.
I also warned against the pitfalls of (1) and even explained  why and how I would use (2) as a temp solution.
All in all hardly "hacky". Although Marco's solution,when polished, is a more elegant one.

Ok, I give you one: back in 1997 when I published similar code to (1) in The UNofficial Delphi newsletter (a.k.a. UNDU) it was indeed meant to be hacky ;) I grew up.
« Last Edit: December 19, 2016, 08:03:18 pm by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: for loop with custom step width (esp. ≠ 1)
« Reply #28 on: December 19, 2016, 08:00:08 pm »
Yeah, this question raised during education. So?
So - let's keep everything. as is!
You can currently achieve the same functionality (loop counter with some step) w/o need of changing the language syntax.

Let's leave adding more and more sugar to the language to Embarcadero. They're very good at it.

Let FPC grow in width (by supporting more and more libraries) rather than in depth (adding more-more language features)

Thaddy

  • Hero Member
  • *****
  • Posts: 14377
  • Sensorship about opinions does not belong here.
Re: for loop with custom step width (esp. ≠ 1)
« Reply #29 on: December 19, 2016, 08:05:18 pm »
Yeah, this question raised during education. So?
So - let's keep everything. as is!
You can currently achieve the same functionality (loop counter with some step) w/o need of changing the language syntax.

Let's leave adding more and more sugar to the language to Embarcadero. They're very good at it.

Let FPC grow in width (by supporting more and more libraries) rather than in depth (adding more-more language features)

Agree. But as me - and Molly too -  wrote: sometimes a step-like syntax comes in handy. Loads of examples in the thread here.
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

 

TinyPortal © 2005-2018