Author Topic: FOR i = 1 TO 0 is slow?  (Read 7154 times)

0 Members and 1 Guest are viewing this topic.

Offline MrFreyer

  • Newbie
  • Posts: 34
    • View Profile
FOR i = 1 TO 0 is slow?
« on: June 05, 2019, 09:56:03 am »
Hi everyone,

I have a performance question about canceled FOR...NEXT loops.

Is this a bad and slow method of programming?
Code: QB64: [Select]
  1. quantity = 0
  2.  
  3. FOR i = 1 TO quantity
  4. '...


...and would this be a faster method?
Code: QB64: [Select]
  1. quantity = 0
  2.  
  3. IF quantity > 0 THEN
  4. FOR i = 1 TO quantity
  5. '...

Thanks!

Marked as best answer by MrFreyer on June 05, 2019, 09:11:30 am

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Re: FOR i = 1 TO 0 is slow?
« Reply #1 on: June 05, 2019, 10:33:10 am »
No difference, if "quantity" is already less than the loop's start counter, then the loop will never be executed, but is skipped immediatly. The program proceeds with the line following the NEXT statement. However if "quantity" is greater than the start counter, then you only would add another (useless) check with the IF...THEN block, hence you are slower with your second example.
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: FOR i = 1 TO 0 is slow?
« Reply #2 on: June 05, 2019, 10:36:24 am »
It depends on what you intended to do.
Code: QB64: [Select]
  1. FOR i = 1 to 0
  2. '...
  3.  
It becomes a infinity type loop. It will continue forever unless you quit the program. If your intention was to move from 1 to 0 in a FOR NEXT loop
then you need to mention the STEP.
This will work -
Code: QB64: [Select]
  1. FOR i = 1 to 0 STEP -1
  2. '...
  3.  
EDIT : Oops. Sorry. This type of loop get skipped in BASIC. Hey, but in other like C++, it does become a forever loop.
« Last Edit: June 05, 2019, 10:38:14 am by Ashish »
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: FOR i = 1 TO 0 is slow?
« Reply #3 on: June 05, 2019, 11:58:46 am »
FOR ...NEXT is slow loop structure, WHILE ...WEND or DO ...LOOP are faster, of course you have to code exit to avoid infinite loop.

Offline MrFreyer

  • Newbie
  • Posts: 34
    • View Profile
Re: FOR i = 1 TO 0 is slow?
« Reply #4 on: June 05, 2019, 01:15:02 pm »
No difference, if "quantity" is already less than the loop's start counter, then the loop will never be executed, but is skipped immediatly. The program proceeds with the line following the NEXT statement. However if "quantity" is greater than the start counter, then you only would add another (useless) check with the IF...THEN block, hence you are slower with your second example.
Okay thanks, good to know.

FOR ...NEXT is slow loop structure, WHILE ...WEND or DO ...LOOP are faster, of course you have to code exit to avoid infinite loop.
So I should never use FOR...NEXT loops? Just DO...LOOPs with an counter as exit condition? Do you know why DO...LOOPs are faster?
I've read that SELECT CASE should also be faster than IF...THEN...ELSEIF (in some cases...). That's also correct?
« Last Edit: June 05, 2019, 01:16:43 pm by MrFreyer »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: FOR i = 1 TO 0 is slow?
« Reply #5 on: June 05, 2019, 02:30:31 pm »
I only mention this if you really need every boost you can get:
Code: QB64: [Select]
  1. PRINT "Running 4 timed tests please wait..."
  2.  
  3. n = 1000000000
  4.  
  5. t! = TIMER
  6. x = 0: i = 0
  7. doloop:
  8. i = i + 1
  9. x = x + i
  10. IF i < n THEN GOTO doloop
  11. t2! = TIMER
  12.  
  13. x = 0: i = 0
  14. WHILE i < n
  15.     i = i + 1
  16.     x = x + i
  17. t3! = TIMER
  18.  
  19. x = 0
  20. FOR i = 0 TO n
  21.     x = x + i
  22. t4! = TIMER
  23.  
  24.  
  25. x = 0: i = 0
  26.     i = i + 1
  27.     x = x + i
  28. LOOP UNTIL i = n
  29. t5! = TIMER
  30.  
  31. PRINT n; "    times adding in Do... LOOP time is "; t5! - t4!
  32. PRINT n; "   times adding in FOR... NEXT time is "; t4! - t3!
  33. PRINT n; " times adding in While... Wend time is "; t3! - t2!
  34. PRINT n; "     times adding in GOTO loop time is "; t2! - t!
  35.  
  36.  

Here are my results in Windows 10 laptop, core i5
  [ You are not allowed to view this attachment ]  
« Last Edit: June 05, 2019, 02:38:35 pm by bplus »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: FOR i = 1 TO 0 is slow?
« Reply #6 on: June 05, 2019, 03:09:27 pm »
DO...LOOP is, indeed, faster than FOR...NEXT statements.

The reason is mainly because of error checking and optional parameters need with FOR.

FOR variable = Start TO Finish STEP value

With the above, the translated C-code does several checks before running.  Is value zero?  Is it less than zero?  Greater than?

If value is less than zero (counting down, like from 10 to 1), then we need to repeat the incremental loop until variable is LESS THAN Finish.  If value is greater than zero, we repeat until GREATER THAN finish...

It’s extra decision making which the translated code runs, which a DO...LOOP structure doesn’t have.  Add in error checking, and it just increases the extra steps going on under the hood with FOR loops.

*******************

For optimized speed, use DO instead of FOR.  When speed isn’t such a concern, use FOR for easy of readability and speed coding.

At least, that’s how I recommend them with QB64.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline MrFreyer

  • Newbie
  • Posts: 34
    • View Profile
Re: FOR i = 1 TO 0 is slow?
« Reply #7 on: June 05, 2019, 04:36:37 pm »
i don't know... :D

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: FOR i = 1 TO 0 is slow?
« Reply #8 on: June 05, 2019, 08:20:39 pm »
Hi McFreyer,

:D  I have to ask, what OS and computer are you using? What version of QB64? 

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: FOR i = 1 TO 0 is slow?
« Reply #9 on: June 05, 2019, 10:40:53 pm »
Run from my laptop with Vista I get rather random results from run to run.
but I think his computer is still better than mine.
Granted after becoming radioactive I only have a half-life!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: FOR i = 1 TO 0 is slow?
« Reply #10 on: June 05, 2019, 11:32:34 pm »
Let's take a moment to look at how our QB64 code translates into C-code.

First, let's start with a simple FOR...NEXT loop:

Code: QB64: [Select]
  1. FOR i = 0 TO 100

Now, we can't get any simpler than this, and even this simple little batch of code turns into the following:

Code: [Select]
S_1:;
fornext_value2= 0 ;
fornext_finalvalue2= 100 ;
fornext_step2= 1 ;
if (fornext_step2<0) fornext_step_negative2=1; else fornext_step_negative2=0;
if (new_error) goto fornext_error2;
goto fornext_entrylabel2;
while(1){
fornext_value2=fornext_step2+(*__SINGLE_I);
fornext_entrylabel2:
*__SINGLE_I=fornext_value2;
if (fornext_step_negative2){
if (fornext_value2<fornext_finalvalue2) break;
}else{
if (fornext_value2>fornext_finalvalue2) break;
}
fornext_error2:;
if(qbevent){evnt(1);if(r)goto S_1;}
fornext_continue_1:;
}
fornext_exit_1:;

As you can see, there's quite a bit of error checking and conditioning checking going on in the code.  Each time the code runs, we have to check to see if the fornext_step_negative2 is negative or not, and then we check to see if our current value is greater (or lesser) than the final value. 

Now, let's compare this code to how a DO...LOOP is translated.  First, let's start with the QB64 code:

Code: QB64: [Select]
  1. i = 0
  2.     i = i + 1
  3. LOOP UNTIL i > 100

And the translation to this simple DO...LOOP code:

Code: [Select]
do{
*__SINGLE_I= 0 ;
if(!qbevent)break;evnt(1);}while(r);
S_2:;
do{
if(qbevent){evnt(2);if(r)goto S_2;}
do{
*__SINGLE_I=*__SINGLE_I+ 1 ;
if(!qbevent)break;evnt(3);}while(r);
S_4:;
dl_continue_1:;
}while((!(-(*__SINGLE_I> 100 )))&&(!new_error));
dl_exit_1:;
if(qbevent){evnt(4);if(r)goto S_4;}

As you can see, there's a lot fewer IF checks going in inside the DO..LOOP, as we don't need to check to see if we're counting up or down with the command.  Those checks are dependent on the user to code what's proper for their needs.

**************************

And, if we turn the checking off, like in the following code, it's even easier to see exactly how large a difference there is in the two processes.

Code: QB64: [Select]
  1. i = 0
  2.     i = i + 1
  3. LOOP UNTIL i > 100
  4.  

With checking off, the above code translates into a very simple little:
Code: [Select]
*__SINGLE_I= 0 ;
do{
*__SINGLE_I=*__SINGLE_I+ 1 ;
dl_continue_1:;
}while((!(-(*__SINGLE_I> 100 )))&&(!new_error));
dl_exit_1:;

And, if we do the same with the FOR..NEXT loop, what we see is the following:

Code: QB64: [Select]

Which translates to:

Code: [Select]
fornext_value2= 0 ;
fornext_finalvalue2= 100 ;
fornext_step2= 1 ;
if (fornext_step2<0) fornext_step_negative2=1; else fornext_step_negative2=0;
if (new_error) goto fornext_error2;
goto fornext_entrylabel2;
while(1){
fornext_value2=fornext_step2+(*__SINGLE_I);
fornext_entrylabel2:
*__SINGLE_I=fornext_value2;
if (fornext_step_negative2){
if (fornext_value2<fornext_finalvalue2) break;
}else{
if (fornext_value2>fornext_finalvalue2) break;
}
fornext_error2:;
fornext_continue_1:;
}
fornext_exit_1:;

Which, once we compare the two routines closely against each other, easily (in my opinion) showcases why the DO...LOOP structure is inherently faster than the FOR...NEXT translation.

************************

As to why some people are seeing faster times with the FOR..NEXT, over the DO...LOOP, I have no idea what's going on.  Logic tells us that it's going to be faster to simply add a value to a number, than it is to add a value to a number and then check to see if it's counting up or down...  DO simply has fewer steps to its process than FOR does. 

Out of curiosity, could you guys who are seeing the faster FOR loops add the $CHECKING:OFF command to Bplus's code and then run it.  I'm curious how much of a delay the internal error checking processes are making on the code.

Tr this, and see how it performs for you folks:

Code: QB64: [Select]
  1. PRINT "Running 4 timed tests please wait..."
  2.  
  3. n = 1000000000
  4.  
  5. t! = TIMER
  6. x = 0: i = 0
  7. doloop:
  8. i = i + 1
  9. x = x + i
  10. IF i < n THEN GOTO doloop
  11. t2! = TIMER
  12.  
  13. x = 0: i = 0
  14. WHILE i < n
  15.     i = i + 1
  16.     x = x + i
  17. t3! = TIMER
  18.  
  19. x = 0
  20. FOR i = 0 TO n
  21.     x = x + i
  22. t4! = TIMER
  23.  
  24.  
  25. x = 0: i = 0
  26.     i = i + 1
  27.     x = x + i
  28. LOOP UNTIL i = n
  29. t5! = TIMER
  30.  
  31. PRINT n; "    times adding in Do... LOOP time is "; t5! - t4!
  32. PRINT n; "   times adding in FOR... NEXT time is "; t4! - t3!
  33. PRINT n; " times adding in While... Wend time is "; t3! - t2!
  34. PRINT n; "     times adding in GOTO loop time is "; t2! - t!
  35.  
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Re: FOR i = 1 TO 0 is slow?
« Reply #11 on: June 06, 2019, 01:46:38 am »
I'm still wondering, why the FOR...NEXT loop has such a bulky (goto label) implementation from QB64 -> C++ level. Wouldn't it be better simply translated into a C++ "for" loop?

Using "goto" in C++ is even more frowned upon than some people already do in BASIC.

counting up:
Code: C: [Select]
  1. for (int i = 0; i <= 100; i++) {
  2.     // do stuff here;
  3. }

counting down:
Code: C: [Select]
  1. for (int i = 100; i >= 0; i--) {
  2.     // do stuff here;
  3. }

or given a STEP (eg. 5):
Code: C: [Select]
  1. for (int i = 0; i <= 100; i+=5) {
  2.     // do stuff here;
  3. }
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: FOR i = 1 TO 0 is slow?
« Reply #12 on: June 06, 2019, 02:44:33 am »
I'm still wondering, why the FOR...NEXT loop has such a bulky (goto label) implementation from QB64 -> C++ level. Wouldn't it be better simply translated into a C++ "for" loop?

Only Galleon knows why he translated some of the commands the way he has.  After all, I also wonder, why does a FOR loop need a temp variable?

Code: [Select]
fornext_value2=fornext_step2+(*__SINGLE_I);
fornext_entrylabel2:
*__SINGLE_I=fornext_value2;

Why not simply let the variable equal the value naturally?  Reduce a few assignment processes each loop.  Why not just a simple:

__SINGLE_I = __SINGLE_I + fornext_step2;

https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline MrFreyer

  • Newbie
  • Posts: 34
    • View Profile
Re: FOR i = 1 TO 0 is slow?
« Reply #13 on: June 06, 2019, 05:03:29 am »
Hi McFreyer,

:D  I have to ask, what OS and computer are you using? What version of QB64?
Windows 10 Laptop, Intel Celeron 2.16GHz, 4GB RAM
QB64 v0.954
I will download the latest version now...

Let's take a moment to look at how our QB64 code translates into C-code.
Thanks for the insight!!!!

EDIT:
the 1.3 version (64 bit) was faster, from 10.6 sec (FOR...NEXT) till 11.9 sec (DO...LOOP)
the FOR...NEXT loop was still the fastest...
« Last Edit: June 06, 2019, 07:09:09 am by MrFreyer »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: FOR i = 1 TO 0 is slow?
« Reply #14 on: June 06, 2019, 09:28:56 am »
Windows 10 Laptop, Intel Celeron 2.16GHz, 4GB RAM
QB64 v0.954
I will download the latest version now...
Thanks for the insight!!!!

EDIT:
the 1.3 version (64 bit) was faster, from 10.6 sec (FOR...NEXT) till 11.9 sec (DO...LOOP)
the FOR...NEXT loop was still the fastest...

Wow such unexpected (by me at least) results.

Quote
Can Celeron processor support Windows 10?
For processing, Windows 10 requires a CPU with a minimum speed of 1GHz. This is a very low bar to clear, as even Intel's low-powered Atom and Celeron processors have been above the 1GHz mark for several years. ... You'll also want to look up whether or not your processor supports a 64-bit operating system.Oct 17, 2017

Well it must support 64 bit or it couldn't run QB64 v1.3 64 bit for Windows, I imagine.

I am interested also in results Steve requested from folks whose FOR ...NEXT loop is running faster than others:
Let's take a moment to look at how our QB64 code translates into C-code.

First, let's start with a simple FOR...NEXT loop:

...

Out of curiosity, could you guys who are seeing the faster FOR loops add the $CHECKING:OFF command to Bplus's code and then run it.  I'm curious how much of a delay the internal error checking processes are making on the code.

Tr this, and see how it performs for you folks:

Code: QB64: [Select]
  1. PRINT "Running 4 timed tests please wait..."
  2.  
  3. n = 1000000000
  4.  
  5. t! = TIMER
  6. x = 0: i = 0
  7. doloop:
  8. i = i + 1
  9. x = x + i
  10. IF i < n THEN GOTO doloop
  11. t2! = TIMER
  12.  
  13. x = 0: i = 0
  14. WHILE i < n
  15.     i = i + 1
  16.     x = x + i
  17. t3! = TIMER
  18.  
  19. x = 0
  20. FOR i = 0 TO n
  21.     x = x + i
  22. t4! = TIMER
  23.  
  24.  
  25. x = 0: i = 0
  26.     i = i + 1
  27.     x = x + i
  28. LOOP UNTIL i = n
  29. t5! = TIMER
  30.  
  31. PRINT n; "    times adding in Do... LOOP time is "; t5! - t4!
  32. PRINT n; "   times adding in FOR... NEXT time is "; t4! - t3!
  33. PRINT n; " times adding in While... Wend time is "; t3! - t2!
  34. PRINT n; "     times adding in GOTO loop time is "; t2! - t!
  35.  
« Last Edit: June 06, 2019, 09:43:28 am by bplus »